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

fittingWnd.py (44507B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fittingScreen\fittingWnd.py
      2 import evetypes
      3 import eveui
      4 import locks
      5 import telemetry
      6 import threadutils
      7 import uthread
      8 import uthread2
      9 from carbon.common.script.sys.serviceConst import ROLE_WORLDMOD, ROLE_GML
     10 from carbon.common.script.util.format import FmtAmt
     11 from carbonui import AxisAlignment, const as uiconst, fontconst
     12 from carbonui.control.buttonIcon import ButtonIcon
     13 from carbonui.control.window import Window
     14 from carbonui.decorative.panelUnderlay import PanelUnderlay
     15 from carbonui.primitives.container import Container
     16 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     17 from carbonui.primitives.frame import Frame
     18 from carbonui.primitives.layoutGrid import LayoutGrid
     19 from carbonui.uicore import uicore
     20 from carbonui.window.header.tab_navigation import TabNavigationWindowHeader
     21 from eve.client.script.ui.control.divider import Divider
     22 from eve.client.script.ui.control.eveLabel import EveLabelMediumBold, EveLabelMedium
     23 from eve.client.script.ui.control.infoIcon import InfoIcon
     24 from eve.client.script.ui.shared.fitting.cosmeticFittingController import CosmeticFittingController
     25 from eve.client.script.ui.shared.fitting.fittingUtil import EatSignalChangingErrors, FTTING_PANEL_SETTING_LEFT_WIDTH, GetBaseShapeSize, GetFittingDragData, GetScaleFactor, GetTypeIDForController, PANEL_WIDTH_DEFAULT, PANEL_WIDTH_MAX, PANEL_WIDTH_MIN, PANEL_WIDTH_RIGHT
     26 from eve.client.script.ui.shared.fittingScreen import TAB_CONFIGNAME_BROWSER, TAB_CONFIGNAME_STATS, TAB_CONFIGNAME_INVENTORY, fittingSignals
     27 from eve.client.script.ui.shared.fittingScreen.baseFitting import FittingCont
     28 from eve.client.script.ui.shared.fittingScreen.cosmetics.cosmeticFitting import CosmeticFitting
     29 from eve.client.script.ui.shared.fittingScreen.dronePickerMenu import DronePickerMenu
     30 from eve.client.script.ui.shared.fittingScreen.fighterPickerMenu import FighterBayItemPickerMenu
     31 from eve.client.script.ui.shared.fittingScreen.filterBtn import GetBtnTypeForFlagID
     32 from eve.client.script.ui.shared.fittingScreen.fittingPanels.minihangar import CargoCargoSlots, CargoDroneSlots, CargoFighterSlots, CargoStructureAmmoBay
     33 from eve.client.script.ui.shared.fittingScreen.fittingUtil import GetColoredText
     34 from eve.client.script.ui.shared.fittingScreen.ghostShipIcon import GhostShipIcon
     35 from eve.client.script.ui.shared.fittingScreen.cosmetics.cosmeticsTab import CosmeticsTab
     36 from eve.client.script.ui.shared.fittingScreen.historyCont import FittingHistoryCont
     37 from eve.client.script.ui.shared.fittingScreen.hullAndHardwareTypeBrowser import FittingHullAndHardwareTypeBrowser
     38 from eve.client.script.ui.shared.fittingScreen.invPanel import FittingInvPanel
     39 from eve.client.script.ui.shared.fittingScreen.itemPickerMenu import CargoItemPickerMenu
     40 from eve.client.script.ui.shared.fittingScreen.serviceCont import FittingServiceCont
     41 from eve.client.script.ui.shared.fittingScreen.settingUtil import GetCurrentLeftPanelKey, GetCurrentRightPanelKey, SetCurrentRightPanelKey, SetCurrentLeftPanelKey
     42 from eve.client.script.ui.shared.fittingScreen.sidePanelButtons import SidePanelTabGroup, SidePanelTabGroupSmall
     43 from eve.client.script.ui.shared.fittingScreen.skillRequirements import GetSkillTooltip, GetMissingSkills_HighestLevelByTypeID, GetAllTypeIDsMissingSkillsForShipAndContent
     44 from eve.client.script.ui.shared.fittingScreen.statsPanel import StatsPanel
     45 from eve.client.script.ui.shared.fittingScreen.warningIconCont import WarningIconCont
     46 from eve.client.script.ui.shared.pointerTool import pointerToolConst as pConst
     47 from eve.client.script.ui.shared.traits import HasTraits, TraitsContainer
     48 from eve.client.script.ui.station.fitting.fittingTooltipUtils import SetFittingTooltipInfo
     49 from eve.client.script.ui.tooltips.tooltipUtil import SetTooltipHeaderAndDescription
     50 from eve.common.script.sys.eveCfg import GetActiveShip
     51 from eveexceptions import UserError
     52 from eveui.decorators import lock_and_set_pending
     53 from localization import GetByLabel
     54 from shipfitting.fittingWarningConst import WARNING_OVER_CPU, WARNING_OVER_POWERGRID
     55 from shipfitting.fittingWarnings import GetColorForLevel
     56 from signals.signalUtil import ChangeSignalConnect
     57 ANIM_DURATION = 0.25
     58 FITTING_MODE_TAB_GROUP_ANALYTIC_ID = 'FittingModeTabGroup'
     59 LEFT_TABS = [TAB_CONFIGNAME_BROWSER, TAB_CONFIGNAME_INVENTORY]
     60 TAB_ID_FITTING = 'equipment'
     61 TAB_ID_COSMETIC = 'personalization'
     62 WND_NORMAL_HEIGHT_BIG = 676
     63 WND_NORMAL_HEIGHT_SMALL = 676
     64 
     65 def OpenFittingWnd(tabID):
     66     wnd = FittingWindow.GetIfOpen()
     67     if wnd and not wnd.destroyed:
     68         wnd.Maximize()
     69     else:
     70         wnd = FittingWindow.Open()
     71     wnd.GoToTab(tabID)
     72 
     73 
     74 class FittingWindow(Window):
     75     __guid__ = 'FittingWindow'
     76     __notifyevents__ = ['OnSetDevice',
     77      'OnSessionChanged',
     78      'OnSimulationChanged',
     79      'OnUIScalingChange',
     80      'OnSkillsChanged',
     81      'OnFittingFlagFilterSet',
     82      'OnCurrentStructureStateChanged']
     83     default_fixedHeight = WND_NORMAL_HEIGHT_BIG
     84     default_windowID = 'fittingWnd'
     85     default_captionLabelPath = 'Tooltips/StationServices/ShipFittingGhost'
     86     default_descriptionLabelPath = 'Tooltips/StationServices/ShipFittingGhost_description'
     87     default_iconNum = 'res:/ui/Texture/WindowIcons/fitting.png'
     88     default_isCollapseable = False
     89     open_fitting_window_tab = None
     90 
     91     def __init__(self, **kwargs):
     92         self._left_side_fill = None
     93         super(FittingWindow, self).__init__(**kwargs)
     94 
     95     def ApplyAttributes(self, attributes):
     96         Window.ApplyAttributes(self, attributes)
     97         self.MakeUnResizeable()
     98         self.windowReady = False
     99         self._controller = None
    100         self.cosmeticController = None
    101         self._layoutLock = locks.Lock()
    102         itemID = attributes.shipID or GetActiveShip()
    103         self.LoadFittingController(itemID)
    104         self.LoadCosmeticController(itemID)
    105         self.LoadWnd()
    106         self.on_content_padding_changed.connect(self._on_content_padding_changed)
    107         fittingSignals.on_find_type_in_browser.connect(self.OnFindTypeInBrowser)
    108 
    109     @property
    110     def controller(self):
    111         return self._controller
    112 
    113     @controller.setter
    114     def controller(self, value):
    115         self._controller = value
    116 
    117     @telemetry.ZONE_METHOD
    118     @eveui.skip_if_destroyed
    119     def LoadWnd(self):
    120         self.ConstructLayout()
    121         if self.destroyed:
    122             return
    123         self.ConstructTabs()
    124         self.LoadLeftPanel(key=None)
    125 
    126     def LoadFittingController(self, shipID):
    127         try:
    128             if self.controller:
    129                 with EatSignalChangingErrors(errorMsg='fitting wnd'):
    130                     self.ChangeSignalConnection(connect=False)
    131                 self.controller.Close()
    132             self.controller = sm.GetService('ghostFittingSvc').LoadGhostFittingController(shipID)
    133         except UserError:
    134             self.Close()
    135             raise
    136 
    137         self._fixedHeight = GetFixedWndHeight(self.controller)
    138         self.ChangeSignalConnection(connect=True)
    139 
    140     def LoadCosmeticController(self, itemID):
    141         self.cosmeticController = CosmeticFittingController(itemID)
    142 
    143     def GoToTab(self, tabID, cosmeticTabID):
    144         self.fittingModeTabGroup.SelectByID(tabID)
    145         if tabID == TAB_ID_COSMETIC and cosmeticTabID is not None:
    146             self.cosmeticsPanel.GoToTab(cosmeticTabID)
    147 
    148     def OnControllerChanging(self, itemID):
    149         self.LoadFittingController(itemID)
    150         if not self.controller.IsSimulated():
    151             self.LoadCosmeticController(itemID)
    152         self.LoadWnd()
    153         if getattr(self, 'warningIconCont', None):
    154             self.warningIconCont.ChangeController(self.controller)
    155         sm.GetService('ghostFittingSvc').SendOnSimulatedShipLoadedEvent(itemID, self.controller.GetTypeID())
    156 
    157     def ChangeSignalConnection(self, connect = True):
    158         signalAndCallback = [(self.controller.on_stats_changed, self.UpdateStatsOnSignal),
    159          (self.controller.on_new_itemID, self.OnNewItem),
    160          (self.controller.on_should_close, self.Close),
    161          (self.controller.on_simulation_state_changed, self.OnSimulationStateChanged),
    162          (self.controller.on_controller_changing, self.OnControllerChanging),
    163          (self.controller.on_name_changed, self.UpdateShipName),
    164          (self.controller.on_warning_display_changed, self.ChangeWarningDisplay)]
    165         ChangeSignalConnect(signalAndCallback, connect)
    166 
    167     def Prepare_Header_(self):
    168         self.header = TabNavigationWindowHeader(on_tab_selected=self.OnFittingModeTabChange)
    169         self.header._line.Hide()
    170 
    171     def ConstructTabs(self):
    172         self.fittingModeTabGroup.Flush()
    173         self.fittingModeTabGroup.AddTab(label=GetByLabel('UI/Fitting/FittingWindow/Fitting'), panel=self.moduleFittingModeContainer, tabID=TAB_ID_FITTING, uniqueName=pConst.UNIQUE_NAME_FITTING_EQUIPMENT)
    174         self.fittingModeTabGroup.AddTab(label=GetByLabel('UI/ShipCosmetics/Personalization'), panel=self.cosmeticFittingModeContainer, tabID=TAB_ID_COSMETIC, tabClass=CosmeticsTab, callback=self.AllowSwitchToCosmeticSection, enabled=not self.controller.ControllerForCategory() == const.categoryStructure, uniqueName=pConst.UNIQUE_NAME_FITTING_PERSONALIZATION)
    175         self.fittingModeTabGroup.AutoSelect()
    176 
    177     @telemetry.ZONE_METHOD
    178     def ConstructLayout(self):
    179         self._fixedHeight = GetFixedWndHeight(self.controller)
    180         self.height = self._fixedHeight
    181         with self._layoutLock:
    182             self.content.Flush()
    183             width = self.GetLeftPanelWidth() if self.IsLeftPanelExpanded() else 0
    184             opacity = 1.0 if self.IsLeftPanelExpanded() else 0.0
    185             padValue = 4
    186             self.fittingModeTabGroup = self.header.tab_group
    187             self.fittingModeTabGroup.analyticID = FITTING_MODE_TAB_GROUP_ANALYTIC_ID
    188             self.fittingModeTabGroup.callback = self.OnFittingModeTabChange
    189             self.moduleFittingModeContainer = Container(name='moduleFittingModeContainer', parent=self.content, align=uiconst.TOALL)
    190             self.cosmeticFittingModeContainer = Container(name='cosmeticFittingModeContainer', parent=self.content, align=uiconst.TOALL)
    191             self.cosmeticFittingModeContainer.Hide()
    192             self.leftPanelCont = Container(name='leftPanelCont', parent=self.moduleFittingModeContainer, align=uiconst.TOLEFT, width=width, opacity=opacity)
    193             self.xDivider = Divider(name='xDivider', parent=self.leftPanelCont, align=uiconst.TORIGHT, width=8, state=uiconst.UI_NORMAL, cross_axis_alignment=AxisAlignment.END)
    194             self.xDivider.Startup(self.leftPanelCont, 'width', 'x', minValue=PANEL_WIDTH_MIN, maxValue=PANEL_WIDTH_MAX)
    195             self.xDivider.OnSizeChanging = self.OnDividerMove
    196             self._left_side_fill = PanelUnderlay(bgParent=self.leftPanelCont, padding=self._get_left_side_fill_padding())
    197             self.leftPanel = FittingHullAndHardwareTypeBrowser(name='leftPanel', parent=self.leftPanelCont, align=uiconst.TOALL, configName=TAB_CONFIGNAME_BROWSER, controller=self.controller)
    198             self.leftPanel.display = False
    199             self.invPanel = FittingInvPanel(name='invPanel', parent=self.leftPanelCont, align=uiconst.TOALL, configName=TAB_CONFIGNAME_INVENTORY, controller=self.controller)
    200             self.invPanel.display = False
    201             self.leftSubPanels = [self.leftPanel, self.invPanel]
    202             width = PANEL_WIDTH_RIGHT if self.IsRightPanelExpanded() else 0
    203             self.rightPanel = StatsPanel(name='rightside', parent=self.moduleFittingModeContainer, align=uiconst.TORIGHT, width=width, controller=self.controller)
    204             mainCont = Container(name='mainCont', parent=self.moduleFittingModeContainer, top=-8)
    205             serviceSlots = {}
    206             if self.controller.ControllerForCategory() == const.categoryStructure:
    207                 self.serviceCont = FittingServiceCont(parent=mainCont, controller=self.controller)
    208                 serviceSlots = self.serviceCont.GetSlotsByFlagID()
    209                 fittingAlignment = uiconst.CENTERTOP
    210             else:
    211                 fittingAlignment = uiconst.CENTER
    212             self.controller.UpdateSlotsByFlagID({flagID:slot.controller for flagID, slot in serviceSlots.iteritems()})
    213             if self.destroyed:
    214                 return
    215             FittingCont(name='FittingContTrue', parent=mainCont, owner=self, controller=self.controller, align=fittingAlignment, serviceSlots=serviceSlots)
    216             if self.destroyed:
    217                 return
    218             overlayWidth, overlayHeight, overlayAlignment = GetOverlayWidthHeightAndAlignment(self.controller)
    219             self.overlayCont = Container(name='overlayCont', parent=mainCont, align=overlayAlignment, width=overlayWidth, height=overlayHeight)
    220             self.fighterAndDroneCont = None
    221             self.ConstructPanelExpanderBtn()
    222             self.ConstructInventoryIcons()
    223             self.ConstructPowerAndCpuLabels()
    224             self.ConstructCurrentGhostIcon(parent=mainCont)
    225             self.ConstructHistoryBar()
    226             if self.destroyed:
    227                 return
    228             self.ConstructNameCaptionAndFittingWarnings(mainCont)
    229             self.windowReady = True
    230             self.width = self.GetWindowWidth()
    231             self.SetFixedWidth(self.width)
    232             self.ChangeHistoryDisplay()
    233             self.UpdateStats()
    234             self.cosmeticsPanel = CosmeticFitting(name='cosmeticsPanel', parent=self.cosmeticFittingModeContainer, align=uiconst.TOALL, cosmeticController=self.cosmeticController, controller=self.controller)
    235 
    236     def AllowSwitchToCosmeticSection(self):
    237         if sm.GetService('fittingSvc').IsShipSimulated():
    238             return sm.GetService('ghostFittingSvc').ShouldContinueAfterAskingAboutSwitchingShips(msg='ExitSimulationWarning')
    239         return True
    240 
    241     def OnFittingModeTabChange(self, newTabID, oldTabID):
    242         if newTabID != oldTabID:
    243             self._NotifyFittingTabChange(newTabID)
    244         if newTabID == TAB_ID_COSMETIC:
    245             self.cosmeticsPanel.PopulateSkinPanel()
    246         if not oldTabID:
    247             self.width = self.GetWindowWidth()
    248             self.SetFixedWidth(self.width)
    249             return
    250         if newTabID != oldTabID:
    251             if newTabID is TAB_ID_COSMETIC and oldTabID is TAB_ID_FITTING:
    252                 if sm.GetService('fittingSvc').IsShipSimulated():
    253                     sm.GetService('ghostFittingSvc').ToggleGhostFitting(askQuestion=False)
    254                 self.cosmeticsPanel.PopulateSkinPanel()
    255                 self._AnimateToCosmeticsSection()
    256             if newTabID is TAB_ID_FITTING and oldTabID is TAB_ID_COSMETIC:
    257                 self._AnimateToEquipmentSection()
    258 
    259     def _NotifyFittingTabChange(self, tabID):
    260         self.open_fitting_window_tab = tabID
    261         sm.ScatterEvent('OnFittingWindowTabChange', self.open_fitting_window_tab)
    262 
    263     def _AnimateToCosmeticsSection(self):
    264         self._fixedWidth = self.GetWindowWidth()
    265         leftDest = self.left
    266         if not self.IsLeftPanelExpanded():
    267             leftDest -= self.GetLeftPanelWidth()
    268         if not self.IsRightPanelExpanded():
    269             leftDest -= PANEL_WIDTH_RIGHT
    270         if self.IsUiScaled():
    271             self.width = self._fixedWidth
    272             self.left = leftDest
    273         else:
    274             uicore.animations.MorphScalar(self, 'width', self.width, self._fixedWidth, duration=ANIM_DURATION)
    275             uicore.animations.MorphScalar(self, 'left', self.left, leftDest, duration=ANIM_DURATION)
    276             uicore.animations.FadeTo(self.cosmeticsPanel.centerParent, startVal=0, endVal=1.0, duration=ANIM_DURATION)
    277 
    278     def _AnimateToEquipmentSection(self):
    279         self._fixedWidth = self.GetWindowWidth()
    280         leftDest = self.left
    281         if not self.IsLeftPanelExpanded():
    282             leftDest += self.GetLeftPanelWidth()
    283         if not self.IsRightPanelExpanded():
    284             leftDest += PANEL_WIDTH_RIGHT
    285         if self.IsUiScaled():
    286             self.width = self._fixedWidth
    287             self.left = leftDest
    288         else:
    289             uicore.animations.MorphScalar(self, 'width', self.width, self._fixedWidth, duration=ANIM_DURATION)
    290             uicore.animations.MorphScalar(self, 'left', self.left, leftDest, duration=ANIM_DURATION)
    291 
    292     def OnDividerMove(self, *args):
    293         settings.user.ui.Set(FTTING_PANEL_SETTING_LEFT_WIDTH, self.leftPanelCont.width)
    294         self.width = self.GetWindowWidth()
    295         self.SetFixedWidth(self.width)
    296 
    297     def LoadLeftPanel(self, key):
    298         if key is None:
    299             key = GetCurrentLeftPanelKey()
    300         for eachPanel in self.leftSubPanels:
    301             if eachPanel.configName != key:
    302                 eachPanel.display = False
    303 
    304         if key == TAB_CONFIGNAME_BROWSER:
    305             self.leftPanel.Load()
    306             self.leftPanel.display = True
    307         elif key == TAB_CONFIGNAME_INVENTORY:
    308             self.invPanel.display = True
    309             self.invPanel.LoadPanel()
    310 
    311     def ConstructInventoryIcons(self):
    312         cargoDroneCont = ContainerAutoSize(name='cargoDroneCont', parent=self.overlayCont, align=uiconst.BOTTOMLEFT, width=110, left=4)
    313         structureInFittingWnd = self.controller.ControllerForCategory() == const.categoryStructure
    314         if structureInFittingWnd:
    315             cargoSlot = CargoStructureAmmoBay(name='structureCargoSlot', parent=cargoDroneCont, align=uiconst.TOTOP, height=32, controller=self.controller, getMenuFunc=self.GetCargoMenu)
    316             configName = 'StructureAmmoHold'
    317             self._SetFittingTooltipInfoForSlot(cargoSlot, configName)
    318         else:
    319             cargoSlot = CargoCargoSlots(name='cargoSlot', parent=cargoDroneCont, align=uiconst.TOTOP, height=32, controller=self.controller, getMenuFunc=self.GetCargoMenu)
    320             self._SetFittingTooltipInfoForSlot(cargoSlot, 'CargoHold')
    321         self.fighterAndDroneCont = Container(name='fighterAndDroneCont', parent=cargoDroneCont, align=uiconst.TOTOP, height=32)
    322         self.ContructDroneAndFighterIcons()
    323 
    324     def _SetFittingTooltipInfoForSlot(self, cargoSlot, configName):
    325         SetFittingTooltipInfo(cargoSlot, configName)
    326         if cargoSlot.itemUtilMenu:
    327             SetFittingTooltipInfo(cargoSlot.itemUtilMenu, configName)
    328 
    329     def ContructDroneAndFighterIcons(self):
    330         self.fighterAndDroneCont.Flush()
    331         structureInFittingWnd = self.controller.ControllerForCategory() == const.categoryStructure
    332         if self.controller.HasFighterBay():
    333             slot = CargoFighterSlots(name='fighterSlot', parent=self.fighterAndDroneCont, align=uiconst.TOTOP, height=32, controller=self.controller, getMenuFunc=self.GetFighterMenu)
    334             tooltipConfigName = 'FighterBayStructure' if structureInFittingWnd else 'FighterBay'
    335             self._SetFittingTooltipInfoForSlot(slot, tooltipConfigName)
    336         else:
    337             slot = CargoDroneSlots(name='droneSlot', parent=self.fighterAndDroneCont, align=uiconst.TOTOP, height=32, controller=self.controller, getMenuFunc=self.GetDroneMenu)
    338             tooltipConfigName = 'DroneBayStructure' if structureInFittingWnd else 'DroneBay'
    339             self._SetFittingTooltipInfoForSlot(slot, tooltipConfigName)
    340         self.fighterOrDroneSlot = slot
    341 
    342     def ReloadDroneAndFighterIconsIfNeeded(self):
    343         if self.fighterAndDroneCont is None:
    344             return
    345         if self.controller.HasFighterBay() and isinstance(self.fighterOrDroneSlot, CargoFighterSlots):
    346             return
    347         if not self.controller.HasFighterBay() and isinstance(self.fighterOrDroneSlot, CargoDroneSlots):
    348             return
    349         self.ContructDroneAndFighterIcons()
    350 
    351     def GetDroneMenu(self, menuParent):
    352         dronePicker = DronePickerMenu(self.controller, menuParent)
    353         menuParent._OnClose = lambda *args: dronePicker.DisconnectController()
    354         dronePicker.LoadItemScroll()
    355         uthread2.StartTasklet(dronePicker.RefrehsScroll)
    356 
    357     def GetCargoMenu(self, menuParent):
    358         itemPicker = CargoItemPickerMenu(self.controller, menuParent)
    359         menuParent._OnClose = lambda *args: itemPicker.DisconnectController()
    360         itemPicker.LoadItemScroll()
    361         uthread2.StartTasklet(itemPicker.RefrehsScroll)
    362 
    363     def GetFighterMenu(self, menuParent):
    364         itemPicker = FighterBayItemPickerMenu(self.controller, menuParent)
    365         menuParent._OnClose = lambda *args: itemPicker.DisconnectController()
    366         itemPicker.LoadItemScroll()
    367         uthread2.StartTasklet(itemPicker.RefrehsScroll)
    368 
    369     def ConstructNameCaptionAndFittingWarnings(self, parent):
    370         cont = Container(name='nameAndWarningsCont', parent=parent, top=8, align=uiconst.TOPLEFT, width=200, height=24)
    371         nameCont = Container(name='nameCont', parent=cont, align=uiconst.TOTOP, height=24)
    372         self.infoLink = InfoIcon(left=4, parent=nameCont, align=uiconst.CENTERLEFT)
    373         self.infoLink.LoadTooltipPanel = self.LoadInfoTooltipPanel
    374         self.infoLink.GetTooltipPointer = lambda *args: uiconst.POINT_RIGHT_2
    375         self.fitNameParent = ContainerAutoSize(name='fitNameParent', parent=nameCont, align=uiconst.CENTERLEFT, alignMode=uiconst.TOPLEFT, left=20, uniqueUiName=pConst.UNIQUE_NAME_CURRENT_FIT, state=uiconst.UI_NORMAL)
    376         self.fitNameParent.OnClick = self.OpenFittingForCurrentShip
    377         self.fitNameParent.GetDragData = GetFittingDragData
    378         self.fitNameParent.isDragObject = True
    379         linkIcon = ButtonIcon(parent=self.fitNameParent, align=uiconst.CENTERLEFT, texturePath='res:/UI/Texture/classes/HyperNet/hyperlink_icon.png', pos=(0, 0, 16, 16), func=self.OpenFittingForCurrentShip, showGlow=False, state=uiconst.UI_DISABLED)
    380         nameLeft = linkIcon.left + linkIcon.width
    381         self.nameCaption = EveLabelMedium(name='nameCaption', parent=self.fitNameParent, text='', align=uiconst.TOPLEFT, left=nameLeft)
    382         w, h = self.nameCaption.MeasureTextSize(text='Xj')
    383         nameCont.height = h + 6
    384         SetTooltipHeaderAndDescription(targetObject=self.fitNameParent, headerText='', descriptionText=GetByLabel('Tooltips/FittingWindow/ShipName_description'))
    385         self.warningIconCont = WarningIconCont(parent=cont, fittingController=self.controller, align=uiconst.TOTOP, padLeft=6)
    386         cont.height += self.warningIconCont.height
    387         self.UpdateShipName()
    388 
    389     def LoadInfoTooltipPanel(self, tooltipPanel, *args):
    390         typeID = self.controller.GetTypeID()
    391         tooltipPanel.LoadGeneric1ColumnTemplate()
    392         tooltipPanel.AddLabelLarge(text='<b>%s</b>' % evetypes.GetName(typeID))
    393         if HasTraits(typeID):
    394             tooltipPanel.AddSpacer(width=300, height=1)
    395             TraitsContainer(parent=tooltipPanel, typeID=typeID, padding=7)
    396 
    397     def LoadSkillTooltip(self, tooltipPanel, *args):
    398         return GetSkillTooltip(tooltipPanel, self.controller, fitName=self.GetFitName())
    399 
    400     def GetFitName(self):
    401         itemID = self.controller.GetItemID()
    402         if isinstance(itemID, long):
    403             return cfg.evelocations.Get(itemID).name
    404         else:
    405             return sm.GetService('ghostFittingSvc').GetShipName()
    406 
    407     def UpdateShipName(self):
    408         typeID = self.controller.GetTypeID()
    409         itemID = self.controller.GetItemID()
    410         name = self.GetFitName()
    411         self.nameCaption.text = name
    412         self.fitNameParent.tooltipPanelClassInfo.headerText = name
    413         self.infoLink.UpdateInfoLink(typeID, itemID)
    414 
    415     @threadutils.throttled(0.5)
    416     def UpdateSkillIcon(self):
    417         if getattr(self, 'haveSkillsIcon', None):
    418             if not self.controller.IsSimulated():
    419                 self.haveSkillsIcon.display = False
    420                 return
    421             self.haveSkillsIcon.display = True
    422             allTypeIDs = GetAllTypeIDsMissingSkillsForShipAndContent(self.controller.GetDogmaLocation())
    423             highestLevelByTypeID, _ = GetMissingSkills_HighestLevelByTypeID(allTypeIDs)
    424             if highestLevelByTypeID:
    425                 self.haveSkillsIcon.texturePath = 'res:/UI/Texture/Icons/38_16_194.png'
    426             else:
    427                 self.haveSkillsIcon.texturePath = 'res:/UI/Texture/Icons/38_16_193.png'
    428 
    429     def OnSkillsChanged(self, *args):
    430         self.UpdateSkillIcon()
    431 
    432     @eveui.skip_if_destroyed
    433     def OnSimulationChanged(self):
    434         self.UpdateShipName()
    435 
    436     def GetModeTooltipPointer(self):
    437         return uiconst.POINT_RIGHT_2
    438 
    439     def ChangeCurrentShipGhostDisplay(self):
    440         self.currentShipGhost.SetShipTypeID()
    441 
    442     def ConstructCurrentGhostIcon(self, parent):
    443         shipTypeID = GetTypeIDForController(session.shipid)
    444         self.currentShipGhost = GhostShipIcon(name='currentShipGhost', parent=parent, controller=self.controller, typeID=shipTypeID, align=uiconst.TOPRIGHT, pos=(11, 15, 64, 64), uniqueUiName=pConst.UNIQUE_NAME_SIMULATE_SHIP)
    445         self.ChangeCurrentShipGhostDisplay()
    446 
    447     def ConstructHistoryBar(self):
    448         historyController = sm.GetService('ghostFittingSvc').historyController
    449         baseSize = GetBaseShapeSize()
    450         multiplier = 0.5
    451         if GetScaleFactor() < 0.85:
    452             multiplier = 0.45
    453         historyWidth = baseSize * multiplier
    454         self.historyCont = FittingHistoryCont(parent=self.overlayCont, align=uiconst.CENTERBOTTOM, historyController=historyController, width=historyWidth)
    455 
    456     def ChangeHistoryDisplay(self):
    457         if self.controller.IsSimulated():
    458             self.historyCont.Show()
    459         else:
    460             self.historyCont.Hide()
    461 
    462     def OnSimulationStateChanged(self):
    463         if self.destroyed:
    464             return
    465         if self.controller.IsSimulated() or self.controller.ControllerForCategory() == const.categoryStructure:
    466             self._DisableCosmeticTab()
    467         else:
    468             self._EnableCosmeticTab()
    469         self.ChangeCurrentShipGhostDisplay()
    470         self.ChangeHistoryDisplay()
    471 
    472     def _DisableCosmeticTab(self):
    473         self.fittingModeTabGroup.CancelAutoSelect()
    474         self.fittingModeTabGroup.SelectByID(TAB_ID_FITTING)
    475         tab = self.fittingModeTabGroup.GetTabByID(TAB_ID_COSMETIC)
    476         if tab:
    477             tab.Disable()
    478 
    479     def _EnableCosmeticTab(self):
    480         tab = self.fittingModeTabGroup.GetTabByID(TAB_ID_COSMETIC)
    481         if tab:
    482             tab.Enable()
    483 
    484     def IsRightPanelExpanded(self):
    485         return GetCurrentRightPanelKey() == TAB_CONFIGNAME_STATS
    486 
    487     def IsLeftPanelExpanded(self):
    488         return GetCurrentLeftPanelKey() in LEFT_TABS
    489 
    490     def GetLeftPanelWidth(self):
    491         panelWidth = settings.user.ui.Get(FTTING_PANEL_SETTING_LEFT_WIDTH, PANEL_WIDTH_DEFAULT)
    492         return min(max(PANEL_WIDTH_MIN, panelWidth), PANEL_WIDTH_MAX)
    493 
    494     def ConstructPanelExpanderBtn(self):
    495         tabBtnData = [(GetByLabel('UI/Fitting/FittingWindow/FittingTab'),
    496           TAB_CONFIGNAME_BROWSER,
    497           'res:/UI/Texture/classes/Fitting/tabHardware.png',
    498           pConst.UNIQUE_NAME_FITTING_BROWSER), (GetByLabel('UI/Fitting/FittingWindow/InvTab'),
    499           TAB_CONFIGNAME_INVENTORY,
    500           'res:/UI/Texture/WindowIcons/items.png',
    501           pConst.UNIQUE_NAME_FITTING_INVENTORY)]
    502         selectedTab = GetCurrentLeftPanelKey()
    503         scaleFactor = GetScaleFactor()
    504         if scaleFactor < 0.8:
    505             sidePanelClass = SidePanelTabGroupSmall
    506         else:
    507             sidePanelClass = SidePanelTabGroup
    508         self.leftPanelTabs = sidePanelClass(parent=self.overlayCont, align=uiconst.CENTERLEFT, top=-160, tabBtnData=tabBtnData, func=self.LeftPanelToggles, left=0, selectedTab=selectedTab, settingName='fittingLeftPanel')
    509         btns = self.leftPanelTabs.GetButtons()
    510         for eachBtnConfig, eachBtn in btns.iteritems():
    511             SetFittingTooltipInfo(eachBtn, eachBtnConfig)
    512 
    513         tabBtnData = [(GetByLabel('UI/Fitting/FittingWindow/StatsTab'),
    514           TAB_CONFIGNAME_STATS,
    515           'res:/UI/Texture/classes/Fitting/filterIconResources.png',
    516           pConst.UNIQUE_NAME_FITING_STATS)]
    517         selectedTab = GetCurrentRightPanelKey()
    518         self.rightPanelTabs = sidePanelClass(parent=self.overlayCont, align=uiconst.CENTERRIGHT, tabBtnData=tabBtnData, top=-140, func=self.ToggleRight, isOnRightOfContent=False, selectedTab=selectedTab, padRight=3, settingName='fittingRightPanel')
    519         btns = self.rightPanelTabs.GetButtons()
    520         for eachBtnConfig, eachBtn in btns.iteritems():
    521             SetFittingTooltipInfo(eachBtn, eachBtnConfig)
    522 
    523     def ToggleRight(self, configName, *args):
    524         currentlyExpaned = self.IsRightPanelExpanded()
    525         if currentlyExpaned:
    526             newValue = ''
    527         else:
    528             newValue = configName
    529         SetCurrentRightPanelKey(newValue)
    530         self._fixedWidth = self.GetWindowWidth()
    531         if currentlyExpaned:
    532             self.CollapseRightPanel()
    533         else:
    534             self.ExpandRightPanel()
    535 
    536     def CollapseRightPanel(self):
    537         self.rightPanelTabs.Disable()
    538         if self.IsUiScaled():
    539             self.rightPanel.opacity = 0.0
    540             self.width = self._fixedWidth
    541             self.rightPanel.width = 0
    542         else:
    543             uicore.animations.FadeTo(self.rightPanel, self.rightPanel.opacity, 0.0, duration=ANIM_DURATION, callback=self.rightPanel.Hide)
    544             uicore.animations.MorphScalar(self, 'width', self.width, self._fixedWidth, duration=ANIM_DURATION)
    545             uicore.animations.MorphScalar(self.rightPanel, 'width', self.rightPanel.width, 0, duration=ANIM_DURATION, sleep=True)
    546         self.rightPanelTabs.Enable()
    547 
    548     def ExpandRightPanel(self):
    549         self.rightPanelTabs.Disable()
    550         self.rightPanel.Show()
    551         if self.IsUiScaled():
    552             self.rightPanel.opacity = 1.0
    553             self.width = self._fixedWidth
    554             self.rightPanel.width = PANEL_WIDTH_RIGHT
    555         else:
    556             uicore.animations.FadeTo(self.rightPanel, self.rightPanel.opacity, 1.0, duration=4 * ANIM_DURATION)
    557             uicore.animations.MorphScalar(self, 'width', self.width, self._fixedWidth, duration=ANIM_DURATION)
    558             uicore.animations.MorphScalar(self.rightPanel, 'width', self.rightPanel.width, PANEL_WIDTH_RIGHT, duration=ANIM_DURATION, sleep=True)
    559         self.rightPanelTabs.Enable()
    560 
    561     def LeftPanelToggles(self, configName, *args):
    562         currentlyShowing = GetCurrentLeftPanelKey()
    563         newSelected = ''
    564         if currentlyShowing and not configName:
    565             SetCurrentLeftPanelKey(newSelected)
    566             self.ColllapseLeftPanel()
    567         elif configName in LEFT_TABS:
    568             newSelected = configName
    569             SetCurrentLeftPanelKey(newSelected)
    570             uthread.new(self.LoadLeftPanel, configName)
    571             if not currentlyShowing:
    572                 self.ExpandLeftPanelTab(configName)
    573 
    574     def ColllapseLeftPanel(self):
    575         self.leftPanelTabs.Disable()
    576         self._fixedWidth = self.GetWindowWidth()
    577         leftPanelWidth = self.GetLeftPanelWidth()
    578         if self.IsUiScaled():
    579             self.leftPanelCont.opacity = 0.0
    580             self.leftPanel.Hide()
    581             self.width = self._fixedWidth
    582             self.left = self.left + leftPanelWidth
    583             self.leftPanelCont.width = 0
    584         else:
    585             uicore.animations.FadeTo(self.leftPanelCont, self.leftPanelCont.opacity, 0.0, duration=0.5 * ANIM_DURATION, callback=self.leftPanel.Hide)
    586             uicore.animations.MorphScalar(self, 'width', self.width, self._fixedWidth, duration=ANIM_DURATION)
    587             uicore.animations.MorphScalar(self, 'left', self.left, self.left + leftPanelWidth, duration=ANIM_DURATION)
    588             uicore.animations.MorphScalar(self.leftPanelCont, 'width', self.leftPanelCont.width, 0, duration=ANIM_DURATION, sleep=True)
    589         self.leftPanelTabs.Enable()
    590 
    591     def ExpandLeftPanelTab(self, configName):
    592         self.leftPanelTabs.Disable()
    593         self._fixedWidth = self.GetWindowWidth()
    594         leftPanelWidth = self.GetLeftPanelWidth()
    595         self.leftPanel.Show()
    596         if self.IsUiScaled():
    597             self.leftPanelCont.opacity = 1.0
    598             self.width = self._fixedWidth
    599             self.left = self.left - leftPanelWidth
    600             self.leftPanelCont.width = leftPanelWidth
    601         else:
    602             uicore.animations.FadeTo(self.leftPanelCont, self.leftPanelCont.opacity, 1.0, duration=4 * ANIM_DURATION)
    603             uicore.animations.MorphScalar(self, 'width', self.width, self._fixedWidth, duration=ANIM_DURATION)
    604             uicore.animations.MorphScalar(self, 'left', self.left, self.left - leftPanelWidth, duration=ANIM_DURATION)
    605             uicore.animations.MorphScalar(self.leftPanelCont, 'width', self.leftPanelCont.width, leftPanelWidth, duration=ANIM_DURATION, sleep=True)
    606         self.leftPanelTabs.Enable()
    607 
    608     def IsUiScaled(self):
    609         return uicore.desktop.dpiScaling != 1.0
    610 
    611     def GetWindowWidth(self):
    612         width = GetBaseShapeSize() * fontconst.fontSizeFactor + 8
    613         cosmeticTabSelected = hasattr(self, 'fittingModeTabGroup') and self.fittingModeTabGroup.GetSelectedID() == TAB_ID_COSMETIC
    614         if self.IsLeftPanelExpanded() or cosmeticTabSelected:
    615             width += self.GetLeftPanelWidth()
    616         if self.IsRightPanelExpanded() or cosmeticTabSelected:
    617             width += PANEL_WIDTH_RIGHT
    618         return width
    619 
    620     def OnSetDevice(self):
    621         if self.controller and self.controller.GetItemID():
    622             uthread.new(self.LoadWnd)
    623 
    624     def OnSessionChanged(self, *args):
    625         if self.destroyed:
    626             return
    627         if session.shipid:
    628             self.currentShipGhost.SetShipTypeID()
    629 
    630     def OnUIScalingChange(self, *args):
    631         if self.controller and self.controller.GetItemID():
    632             uthread.new(self.LoadWnd)
    633 
    634     def InitializeStatesAndPosition(self, *args, **kw):
    635         current = self.GetRegisteredPositionAndSize()
    636         default = self.GetDefaultSizeAndPosition()
    637         fixedHeight = self._fixedHeight
    638         fixedWidth = self.GetWindowWidth()
    639         Window.InitializeStatesAndPosition(self, *args, **kw)
    640         if fixedWidth is not None:
    641             self.width = fixedWidth
    642             self._fixedWidth = fixedWidth
    643         if fixedHeight is not None:
    644             self.height = fixedHeight
    645             self._fixedHeight = fixedHeight
    646         if list(default) == list(current)[:4]:
    647             settings.user.ui.Set('defaultFittingPosition', 1)
    648             dw = uicore.desktop.width
    649             dh = uicore.desktop.height
    650             self.left = (dw - self.width) / 2
    651             self.top = (dh - self.height) / 2
    652 
    653     def _OnClose(self, *args):
    654         settings.user.ui.Set('defaultFittingPosition', 0)
    655 
    656     def MouseDown(self, *args):
    657         uthread.new(uicore.registry.SetFocus, self)
    658         self.SetOrder(0)
    659 
    660     def PreviewFitItem(self, ghostItem = None, force = False):
    661         if not self.controller:
    662             return
    663         self.controller.SetPreviewFittedItem(ghostItem, force)
    664 
    665     def OnStartMinimize_(self, *args):
    666         sm.ChainEvent('ProcessFittingWindowStartMinimize')
    667 
    668     def OnEndMinimize_(self, *args):
    669         sm.ChainEvent('ProcessFittingWindowEndMinimize')
    670 
    671     def OnNewItem(self, *args):
    672         if not self.windowReady:
    673             return
    674         self.currentShipGhost.state = uiconst.UI_DISABLED
    675         self.currentShipGhost.EnableButtonWithDelay()
    676         self.currentShipGhost.SetShipTypeID()
    677         self.UpdateStats()
    678         self.UpdateShipName()
    679 
    680     def UpdateStatsOnSignal(self):
    681         uthread.new(self.UpdateStats)
    682 
    683     @lock_and_set_pending()
    684     def UpdateStats(self):
    685         if not self.windowReady or not self.controller.CurrentShipIsLoaded():
    686             return
    687         self.UpdateCPU()
    688         self.UpdatePower()
    689         self.ReloadDroneAndFighterIconsIfNeeded()
    690         self.UpdateSkillIcon()
    691         if getattr(self, 'warningIconCont', None):
    692             self.warningIconCont.UpdateIcon(self.controller)
    693 
    694     def ConstructPowerAndCpuLabels(self):
    695         powerGridAndCpuCont = LayoutGrid(name='powerGridAndCpuCont', parent=self.overlayCont, columns=1, state=uiconst.UI_PICKCHILDREN, align=uiconst.BOTTOMRIGHT, left=4)
    696         cpu_statustextHeader = EveLabelMediumBold(text=GetByLabel('UI/Fitting/FittingWindow/CPUStatusHeader'), name='cpu_statustextHeader', state=uiconst.UI_NORMAL, align=uiconst.TOPRIGHT)
    697         SetFittingTooltipInfo(targetObject=cpu_statustextHeader, tooltipName='CPU')
    698         powerGridAndCpuCont.AddCell(cpu_statustextHeader)
    699         self.cpu_statustext = EveLabelMedium(text='', name='cpu_statustext', state=uiconst.UI_NORMAL, align=uiconst.TOPRIGHT)
    700         SetFittingTooltipInfo(targetObject=self.cpu_statustext, tooltipName='CPU')
    701         cell = powerGridAndCpuCont.AddCell(self.cpu_statustext)
    702         self.cpu_warningFrame = self.BuildFrame(cpu_statustextHeader, cell)
    703         powerGridAndCpuCont.AddCell(cellObject=Container(name='spacer', align=uiconst.TOTOP, height=10))
    704         power_statustextHeader = EveLabelMediumBold(text=GetByLabel('UI/Fitting/FittingWindow/PowergridHeader'), name='power_statustextHeader', state=uiconst.UI_NORMAL, align=uiconst.TOPRIGHT)
    705         SetFittingTooltipInfo(targetObject=power_statustextHeader, tooltipName='PowerGrid')
    706         powerGridAndCpuCont.AddCell(power_statustextHeader)
    707         self.power_statustext = EveLabelMedium(text='', name='power_statustext', state=uiconst.UI_NORMAL, align=uiconst.TOPRIGHT)
    708         cell = powerGridAndCpuCont.AddCell(self.power_statustext)
    709         self.power_warningFrame = self.BuildFrame(power_statustextHeader, cell)
    710         SetFittingTooltipInfo(targetObject=self.power_statustext, tooltipName='PowerGrid')
    711         self.calibration_statustext = EveLabelMedium(text='', parent=self.overlayCont, name='calibrationstatustext', pos=(8, 54, 0, 0), state=uiconst.UI_NORMAL)
    712         SetFittingTooltipInfo(targetObject=self.calibration_statustext, tooltipName='Calibration')
    713 
    714     def BuildFrame(self, textAbove, cell):
    715         topPadding = -(textAbove.textheight + 3)
    716         f = Frame(parent=cell, frameConst=uiconst.FRAME_BORDER1_CORNER9, padding=(-6,
    717          topPadding,
    718          -6,
    719          -2))
    720         f.display = False
    721         return f
    722 
    723     def UpdateCPU(self):
    724         cpuLoadInfo = self.controller.GetCPULoad()
    725         cpuOutputInfo = self.controller.GetCPUOutput()
    726         cpuDiff = cpuOutputInfo.value - cpuLoadInfo.value
    727         coloredCpuLoadText = self._GetColoredDiffForCpuOrPower(cpuLoadInfo.isBetterThanBefore, cpuDiff)
    728         cpuOutputText = FmtAmt(cpuOutputInfo.value, showFraction=1)
    729         coloredCpuOutputText = GetColoredText(isBetter=cpuOutputInfo.isBetterThanBefore, text=cpuOutputText)
    730         self.SetCpuOrPowerLabel(self.cpu_statustext, cpuDiff, coloredCpuLoadText, coloredCpuOutputText)
    731 
    732     def UpdatePower(self):
    733         powerLoadInfo = self.controller.GetPowerLoad()
    734         powerOutputInfo = self.controller.GetPowerOutput()
    735         powerDiff = powerOutputInfo.value - powerLoadInfo.value
    736         coloredPowerLoadText = self._GetColoredDiffForCpuOrPower(powerLoadInfo.isBetterThanBefore, powerDiff)
    737         powerOutputText = FmtAmt(powerOutputInfo.value, showFraction=1)
    738         coloredPowerOutputText = GetColoredText(isBetter=powerOutputInfo.isBetterThanBefore, text=powerOutputText)
    739         self.SetCpuOrPowerLabel(self.power_statustext, powerDiff, coloredPowerLoadText, coloredPowerOutputText)
    740 
    741     def _GetColoredDiffForCpuOrPower(self, betterThanBefore, diff):
    742         loadText = FmtAmt(diff, showFraction=1)
    743         if betterThanBefore is None and diff < 0:
    744             betterThanBefore = False
    745         coloredCpuLoadText = GetColoredText(isBetter=betterThanBefore, text=loadText)
    746         return coloredCpuLoadText
    747 
    748     def SetCpuOrPowerLabel(self, labelObject, diff, loadText, outputText):
    749         labelObject.text = '%s/%s' % (loadText, outputText)
    750         if diff < 0:
    751             uicore.animations.FadeTo(labelObject.parent, 0.25, 1.0, duration=0.5, loops=uiconst.ANIM_REPEAT)
    752         else:
    753             labelObject.parent.StopAnimations()
    754             labelObject.parent.opacity = 1.0
    755 
    756     def OnFindTypeInBrowser(self, typeID):
    757         self.TryExpandLeftSide()
    758         if GetCurrentLeftPanelKey() == TAB_CONFIGNAME_INVENTORY:
    759             self.invPanel.FindTypeInInventory(typeID)
    760         else:
    761             self.leftPanel.FindTypeInList(typeID)
    762 
    763     def OnFittingFlagFilterSet(self, flagID):
    764         self.TryExpandLeftSide()
    765         btn_type = GetBtnTypeForFlagID(flagID)
    766         if GetCurrentLeftPanelKey() == TAB_CONFIGNAME_INVENTORY:
    767             self.invPanel.enable_one_module_filter_type(btn_type)
    768         else:
    769             self.leftPanel.enable_one_module_filter_type(btn_type)
    770 
    771     def TryExpandLeftSide(self):
    772         currentlyShowing = GetCurrentLeftPanelKey()
    773         if currentlyShowing not in (TAB_CONFIGNAME_BROWSER, TAB_CONFIGNAME_INVENTORY):
    774             btns = self.leftPanelTabs.GetButtons()
    775             browserBtn = btns.get(TAB_CONFIGNAME_BROWSER)
    776             if browserBtn:
    777                 browserBtn.OnClick()
    778 
    779     def GetMenu(self, *args):
    780         m = Window.GetMenu(self, *args)
    781         m += [None]
    782         if session.role & (ROLE_GML | ROLE_WORLDMOD):
    783             m += [('Debug: Reset all search variables', self.ResetAllSearchVariables, ())]
    784             m += [('Debug: Clear resources dictionary', self.ClearResoureDict, ())]
    785             m += [('Debug: Reload ghostfitting DL', self.ReloadFittingDogmaLocation, ())]
    786         return m
    787 
    788     def ClearResoureDict(self):
    789         sm.GetService('fittingSvc').searchFittingHelper.ResetCpuAndPowergridDicts()
    790 
    791     def ResetAllSearchVariables(self):
    792         sm.GetService('fittingSvc').searchFittingHelper.ResetAllVariables()
    793 
    794     def ReloadFittingDogmaLocation(self):
    795         sm.GetService('ghostFittingSvc').ResetFittingDomaLocation(force=True)
    796         sm.GetService('fittingSvc').SetSimulationState(simulationOn=False)
    797         itemID = GetActiveShip()
    798         self.OnControllerChanging(itemID)
    799 
    800     def Close(self, setClosed = False, *args, **kwds):
    801         fittingSvc = sm.GetService('fittingSvc')
    802         ghostFittingSvc = sm.GetService('ghostFittingSvc')
    803         if fittingSvc.IsShipSimulated():
    804             if not ghostFittingSvc.ShouldContinueAfterAskingAboutSwitchingShips(msg='ExitSimulationWarning'):
    805                 return
    806         with EatSignalChangingErrors(errorMsg='ghost fitting wnd'):
    807             if self.controller:
    808                 self.ChangeSignalConnection(connect=False)
    809         try:
    810             ghostFittingSvc.ResetGhostFittingController()
    811             if self.controller:
    812                 self.controller.Close()
    813         finally:
    814             Window.Close(self, setClosed, *args, **kwds)
    815             fittingSvc.SetSimulationState(False)
    816             ghostFittingSvc.ResetSimulationChangedFlag()
    817 
    818     def OpenFittingForCurrentShip(self, *args):
    819         sm.GetService('fittingSvc').DoSaveFitting()
    820 
    821     def ChangeWarningDisplay(self, warningModuleSlotDict, *args):
    822         for frame, warningID in ((self.cpu_warningFrame, -WARNING_OVER_CPU), (self.power_warningFrame, -WARNING_OVER_POWERGRID)):
    823             warningLevel = warningModuleSlotDict.get(warningID, None)
    824             if warningLevel:
    825                 color = GetColorForLevel(warningLevel)
    826                 frame.display = True
    827                 frame.SetRGBA(*color)
    828             else:
    829                 frame.display = False
    830 
    831     def OnBack(self):
    832         if GetCurrentLeftPanelKey() == TAB_CONFIGNAME_INVENTORY:
    833             self.invPanel.OnBack()
    834 
    835     def OnForward(self):
    836         if GetCurrentLeftPanelKey() == TAB_CONFIGNAME_INVENTORY:
    837             self.invPanel.OnForward()
    838 
    839     def _on_content_padding_changed(self, window):
    840         if self.cosmeticsPanel:
    841             self.cosmeticsPanel.AdjustErrorScreenPadding(self.content_padding)
    842         if self._left_side_fill is not None:
    843             self._left_side_fill.padding = self._get_left_side_fill_padding()
    844 
    845     def _get_left_side_fill_padding(self):
    846         pad_left, pad_top, _, pad_bottom = self.content_padding
    847         return (-pad_left,
    848          -pad_top,
    849          0,
    850          -pad_bottom)
    851 
    852 
    853 def GetFixedWndHeight(controller):
    854     if GetScaleFactor() > 0.85:
    855         normalHeight = WND_NORMAL_HEIGHT_BIG
    856     else:
    857         normalHeight = WND_NORMAL_HEIGHT_SMALL
    858     baseSize = GetBaseShapeSize()
    859     if controller.ControllerForCategory() == const.categoryStructure:
    860         return max(baseSize + 85, normalHeight)
    861     return normalHeight
    862 
    863 
    864 def GetOverlayWidthHeightAndAlignment(controller):
    865     fixedHeight = GetFixedWndHeight(controller)
    866     baseSize = GetBaseShapeSize()
    867     if controller.ControllerForCategory() == const.categoryStructure:
    868         width = baseSize * fontconst.fontSizeFactor - 28
    869         height = min(fixedHeight - 12, baseSize)
    870         overlayAlignment = uiconst.CENTERTOP
    871     else:
    872         height = 0
    873         width = 0
    874         overlayAlignment = uiconst.TOALL
    875     return (width, height, overlayAlignment)