class Industry(Window):
    __guid__ = 'form.Industry'
    __notifyevents__ = [
        'OnIndustryLeftOrRightKey', 'OnIndustryDropData',
        'OnIndustryRemoveBlueprint', 'OnIndustryJob', 'OnBlueprintReload',
        'OnFacilityReload', 'OnBlueprintEntryDblClicked'
    ]
    default_captionLabelPath = 'UI/Industry/Industry'
    default_descriptionLabelPath = 'UI/Industry/IndustryTooltip'
    default_caption = localization.GetByLabel('UI/Industry/Industry')
    default_windowID = 'industryWnd'
    default_iconNum = 'res:/UI/Texture/WindowIcons/Industry.png'
    default_height = 800
    default_topParentHeight = 0
    default_isStackable = False
    default_minSize = (1004, 650)

    def ApplyAttributes(self, attributes):
        Window.ApplyAttributes(self, attributes)
        blueprintID = attributes.Get('blueprintID', None)
        blueprintTypeID = attributes.Get('blueprintTypeID', None)
        bpData = attributes.Get('bpData', None)
        self.history = HistoryBuffer()
        self.jobData = None
        self.pendingBlueprint = None
        self.loadBlueprintThread = None
        self.topCont = Container(name='topCont',
                                 parent=self.sr.main,
                                 align=uiconst.TOTOP,
                                 height=TOP_HEIGHT,
                                 clipChildren=True)
        self.currView = BaseView(parent=self.topCont,
                                 align=uiconst.TOTOP,
                                 height=VIEW_HEIGHT)
        self.jobsStrip = JobsStrip(parent=self.topCont,
                                   align=uiconst.TOTOP,
                                   padding=(5, -1, 7, 2),
                                   callback=self.OnBlueprintsSelected)
        self.bottomCont = Container(name='bottomCont',
                                    parent=self.sr.main,
                                    controller=self,
                                    height=0.4,
                                    padding=(4, 0, 4, 0),
                                    callback=self.OnBlueprintsSelected)
        cont = ContainerAutoSize(name='historyArrowCont',
                                 parent=self.sr.main,
                                 align=uiconst.TOPRIGHT,
                                 height=16,
                                 left=3,
                                 top=1)
        self.expandViewBtn = ButtonIcon(
            name='expandViewBtn',
            parent=cont,
            align=uiconst.TORIGHT,
            width=16,
            iconSize=7,
            texturePath='res:/UI/Texture/classes/Neocom/arrowDown.png',
            func=self.OnExpandViewBtn)
        self.goForwardBtn = ButtonIcon(
            name='goForwardBtn',
            parent=cont,
            align=uiconst.TORIGHT,
            width=16,
            iconSize=16,
            padRight=5,
            texturePath='res:/UI/Texture/icons/38_16_224.png',
            func=self.OnForward,
            hint=localization.GetByLabel('UI/Control/EveWindow/Next'))
        self.goBackBtn = ButtonIcon(
            name='goBackBtn',
            parent=cont,
            align=uiconst.TORIGHT,
            width=16,
            iconSize=16,
            texturePath='res:/UI/Texture/icons/38_16_223.png',
            func=self.OnBack,
            hint=localization.GetByLabel('UI/Control/EveWindow/Previous'))
        self.browserCont = Container(name='browserCont',
                                     parent=self.bottomCont,
                                     padding=(0, 2, 0, 2))
        self.browserBlueprints = BrowserBlueprints(
            parent=self.browserCont, callback=self.OnBlueprintsSelected)
        self.browserFacilities = BrowserFacilities(
            parent=self.browserCont, callback=self.OnFacilitySelected)
        self.browserJobs = BrowserJobs(parent=self.browserCont,
                                       callback=self.OnJobSelected)
        tabs = ((localization.GetByLabel('UI/Industry/Blueprints'),
                 self.browserBlueprints, None, 'blueprints', None,
                 GetByLabel('UI/Industry/TabBlueprints')),
                (localization.GetByLabel('UI/Industry/Facilities'),
                 self.browserFacilities, None, 'facilities', None,
                 GetByLabel('UI/Industry/TabFacilities')),
                (localization.GetByLabel('UI/Industry/Jobs'), self.browserJobs,
                 None, 'jobs', None, GetByLabel('UI/Industry/TabJobs')))
        self.tabs = TabGroup(parent=self.browserCont,
                             tabs=tabs,
                             height=26,
                             labelPadding=12,
                             idx=0,
                             padLeft=0,
                             groupID='IndustryWindowBrowsers',
                             autoselecttab=not self.IsBrowserCollapsed())
        self.expandBottomBtn = ButtonIcon(
            name='expandBottomBtn',
            parent=self.bottomCont,
            align=uiconst.TOPRIGHT,
            pos=(2, -3, 16, 16),
            iconSize=7,
            texturePath='res:/UI/Texture/classes/Neocom/arrowDown.png',
            func=self.OnExpandBottomBtn)
        if blueprintID or blueprintTypeID:
            self.ShowBlueprint(blueprintID, blueprintTypeID, bpData=bpData)
        if self.IsViewCollapsed():
            self.CollapseView(animate=False)
        else:
            self.expandViewBtn.SetRotation(-pi)
        if self.IsBrowserCollapsed():
            self.CollapseBrowser(animate=False)
        else:
            self.expandBottomBtn.SetRotation(-pi)
        sm.GetService('audio').SendUIEvent('ind_windowOpened')

    def Close(self, *args, **kwargs):
        Window.Close(self, *args, **kwargs)
        if self.jobData:
            sm.GetService('industrySvc').DisconnectJob(self.jobData)

    @telemetry.ZONE_METHOD
    def OnNewJobData(self, branchHistory=True):
        if self.jobData:
            settings.user.ui.Set('IndustryCurrentActivityID',
                                 self.jobData.activityID)
        self.jobsStrip.OnNewJobData(self.jobData)
        self.currView.OnNewJobData(self.jobData)
        self.browserBlueprints.OnNewJobData(self.jobData)
        if branchHistory and self.jobData:
            self.history.Append((self.jobData.blueprintID,
                                 self.jobData.blueprint.blueprintTypeID,
                                 self.jobData.activityID))
            self.UpdateHistoryButtons()

    @telemetry.ZONE_METHOD
    def OnBlueprintsSelected(self,
                             bpData,
                             activityID=None,
                             branchHistory=True):
        self.pendingBlueprint = (bpData, activityID, branchHistory)
        if not self.loadBlueprintThread:
            self.loadBlueprintThread = uthread.new(self._OnBlueprintSelected)

    def _OnBlueprintSelected(self):
        try:
            while self.pendingBlueprint:
                while uicore.uilib.Key(uiconst.VK_UP) or uicore.uilib.Key(
                        uiconst.VK_DOWN):
                    blue.synchro.Yield()

                bpData, activityID, branchHistory = self.pendingBlueprint
                self.pendingBlueprint = None
                if activityID is None:
                    activityID = self._GetDefaultActivityID(bpData)
                if self.jobData and self.jobData.blueprint.IsSameBlueprint(
                        bpData):
                    if activityID == self.jobData.activityID:
                        break
                self.jobData = None
                if bpData.jobID is not None:
                    jobData = sm.GetService('industrySvc').GetJobByID(
                        bpData.jobID)
                    if jobData.status < industry.STATUS_COMPLETED:
                        self.jobData = sm.GetService(
                            'industrySvc').JobDataWithBlueprint(jobData)
                if not self.jobData:
                    self.jobData = self.CreateJob(bpData, activityID)
                if not self.pendingBlueprint:
                    self.browserBlueprints.OnActivitySelected(
                        self.jobData.blueprintID, activityID)
                    self.OnNewJobData(branchHistory)
                blue.synchro.SleepWallclock(500)

        finally:
            self.loadBlueprintThread = None

    @telemetry.ZONE_METHOD
    def OnFacilitySelected(self, facilityData):
        if self.jobData:
            self.jobData.facility = facilityData

    @telemetry.ZONE_METHOD
    def OnJobSelected(self, jobData):
        if jobData.status > industry.STATUS_COMPLETED:
            jobData = sm.GetService('industrySvc').RecreateJob(jobData)
        else:
            jobData = sm.GetService('industrySvc').JobDataWithBlueprint(
                jobData)
        if not jobData:
            return
        self.jobData = jobData
        self.OnNewJobData(jobData)
        self.UpdateBlueprintBrowserActivitySelected()

    @telemetry.ZONE_METHOD
    def UpdateBlueprintBrowserActivitySelected(self):
        if self.jobData:
            self.browserBlueprints.OnActivitySelected(self.jobData.blueprintID,
                                                      self.jobData.activityID)

    def OnBlueprintEntryDblClicked(self):
        if self.IsViewCollapsed():
            self.ExpandView()

    def _GetDefaultActivityID(self, bpData):
        currActivityID = settings.user.ui.Get('IndustryCurrentActivityID',
                                              None)
        if currActivityID in bpData.activities:
            return currActivityID
        for activityID in industry.ACTIVITIES:
            if activityID in bpData.activities:
                return activityID

    @telemetry.ZONE_METHOD
    def CreateJob(self, bpData, activityID):
        return sm.GetService('industrySvc').CreateJob(bpData, activityID,
                                                      bpData.facilityID)

    def ShowBlueprint(self,
                      blueprintID=None,
                      blueprintTypeID=None,
                      activityID=None,
                      branchHistory=True,
                      bpData=None):
        if not bpData:
            if blueprintID:
                bpData = sm.GetService('blueprintSvc').GetBlueprintItem(
                    blueprintID)
            else:
                bpData = sm.GetService('blueprintSvc').GetBlueprintTypeCopy(
                    blueprintTypeID)
        self.OnBlueprintsSelected(bpData,
                                  activityID=activityID,
                                  branchHistory=branchHistory)

    def ShowJob(self, jobID):
        if jobID:
            self.OnJobSelected(sm.GetService('industrySvc').GetJobByID(jobID))

    @classmethod
    def OpenOrShowBlueprint(cls,
                            blueprintID=None,
                            blueprintTypeID=None,
                            bpData=None):
        wnd = cls.GetIfOpen()
        if wnd:
            wnd.Maximize()
            wnd.ShowBlueprint(blueprintID, blueprintTypeID, bpData=bpData)
            if wnd.IsViewCollapsed():
                wnd.ExpandView()
            uicore.registry.SetFocus(wnd)
        else:
            wnd = cls.Open(blueprintID=blueprintID,
                           blueprintTypeID=blueprintTypeID,
                           bpData=bpData)
            wnd.Maximize()

    def OnExpandBottomBtn(self, *args):
        if self.IsBrowserCollapsed():
            self.ExpandBrowser()
        else:
            self.CollapseBrowser()

    def OnExpandViewBtn(self, *args):
        if self.IsViewCollapsed():
            self.ExpandView()
        else:
            self.CollapseView()

    def ExpandView(self, animate=True):
        settings.user.ui.Set('industryWndIsViewCollapsed', False)
        sm.ScatterEvent('OnIndustryViewExpandCollapse')
        self.expandViewBtn.SetRotation(-pi)
        self.expandViewBtn.Disable()
        self.topCont.Show()
        if animate:
            uicore.animations.MorphScalar(self.topCont,
                                          'height',
                                          self.topCont.height,
                                          TOP_HEIGHT,
                                          duration=0.3)
            uicore.animations.FadeIn(self.topCont, duration=0.3, sleep=True)
        else:
            self.topCont.height = TOP_HEIGHT
            self.topCont.opacity = 1.0
        self.expandBottomBtn.Show()
        self.expandViewBtn.Enable()

    def CollapseView(self, animate=True):
        settings.user.ui.Set('industryWndIsViewCollapsed', True)
        sm.ScatterEvent('OnIndustryViewExpandCollapse')
        self.expandViewBtn.Disable()
        self.expandViewBtn.SetRotation(0)
        self.expandBottomBtn.Hide()
        if animate:
            uicore.animations.MorphScalar(self.topCont,
                                          'height',
                                          self.topCont.height,
                                          0,
                                          duration=0.3)
            uicore.animations.FadeOut(self.topCont, duration=0.3, sleep=True)
        else:
            self.topCont.height = 0
            self.topCont.opacity = 0.0
        self.topCont.Hide()
        self.expandViewBtn.Enable()

    def IsViewCollapsed(self):
        return settings.user.ui.Get('industryWndIsViewCollapsed', False)

    def ExpandBrowser(self, animate=True):
        if self.tabs.GetSelectedIdx() is None:
            self.tabs.AutoSelect()
        settings.user.ui.Set('industryWndIsBrowserCollapsed', False)
        self.expandBottomBtn.SetRotation(-pi)
        self.expandBottomBtn.Disable()
        height = settings.user.ui.Get('industryWndExpandedHeight',
                                      self.default_height)
        self.browserCont.Show()
        if animate:
            uicore.animations.MorphScalar(self,
                                          'height',
                                          self.height,
                                          height,
                                          duration=0.3)
            uicore.animations.FadeIn(self.browserCont,
                                     duration=0.3,
                                     sleep=True)
        else:
            self.height = height
            self.browserCont.opacity = 1.0
        self.UnlockHeight()
        self.expandViewBtn.Show()
        self.expandBottomBtn.Enable()

    def CollapseBrowser(self, animate=True):
        if not self.IsBrowserCollapsed():
            settings.user.ui.Set('industryWndExpandedHeight', self.height)
        settings.user.ui.Set('industryWndIsBrowserCollapsed', True)
        self.expandBottomBtn.Disable()
        self.expandBottomBtn.SetRotation(0)
        self.expandViewBtn.Hide()
        if animate:
            uicore.animations.MorphScalar(self,
                                          'height',
                                          self.height,
                                          FIXED_HEIGHT,
                                          duration=0.3)
            uicore.animations.FadeOut(self.browserCont,
                                      duration=0.3,
                                      sleep=True)
        else:
            self.height = FIXED_HEIGHT
            self.browserCont.opacity = 0.0
        self.LockHeight(FIXED_HEIGHT)
        self.browserCont.Hide()
        self.expandBottomBtn.Enable()

    def IsBrowserCollapsed(self):
        return settings.user.ui.Get('industryWndIsBrowserCollapsed', False)

    def OnBack(self):
        historyID = self.history.GoBack()
        if historyID:
            if uicore.uilib.mouseOver != self.goBackBtn:
                self.goBackBtn.Blink()
            self.ShowBlueprint(branchHistory=False, *historyID)
            self.UpdateHistoryButtons()

    def OnForward(self):
        historyID = self.history.GoForward()
        if historyID:
            if uicore.uilib.mouseOver != self.goForwardBtn:
                self.goForwardBtn.Blink()
            self.ShowBlueprint(branchHistory=False, *historyID)
            self.UpdateHistoryButtons()

    def UpdateHistoryButtons(self):
        if self.history.IsBackEnabled():
            self.goBackBtn.Enable()
        else:
            self.goBackBtn.Disable()
        if self.history.IsForwardEnabled():
            self.goForwardBtn.Enable()
        else:
            self.goForwardBtn.Disable()

    def OnMouseWheel(self, *args):
        sm.ScatterEvent('OnIndustryWndMouseWheel')

    def OnClick(self, *args):
        sm.ScatterEvent('OnIndustryWndClick')

    def CloseByUser(self, *args):
        sm.GetService('audio').SendUIEvent('ind_windowClosed')
        Window.CloseByUser(self, *args)

    def _GetCurrentActivities(self):
        """
        Returns available activities for current blueprint correctly sorted
        """
        currActivities = self.jobData.blueprint.activities.keys()
        currActivities = sorted(currActivities,
                                key=lambda x: ACTIVITIES.index(x))
        return currActivities

    def SelectPreviousActivity(self):
        if not self.jobData or self.jobData.IsInstalled():
            return
        currActivities = self._GetCurrentActivities()
        idx = currActivities.index(self.jobData.activityID)
        if idx == 0:
            return
        activityID = currActivities[idx - 1]
        self._SelectActivity(activityID)

    def SelectNextActivity(self):
        if not self.jobData or self.jobData.IsInstalled():
            return
        currActivities = self._GetCurrentActivities()
        idx = currActivities.index(self.jobData.activityID)
        if idx == len(currActivities) - 1:
            return
        activityID = currActivities[idx + 1]
        self._SelectActivity(activityID)

    def _SelectActivity(self, activityID):
        self.browserBlueprints.OnActivitySelected(self.jobData.blueprintID,
                                                  activityID)
        self.OnBlueprintsSelected(self.jobData.blueprint, activityID)

    def OnIndustryLeftOrRightKey(self, key):
        if key == uiconst.VK_LEFT:
            self.SelectPreviousActivity()
        elif key == uiconst.VK_RIGHT:
            self.SelectNextActivity()

    def OnDropData(self, dragSource, dragData):
        if not dragData:
            return
        typeID = itemID = None
        data = dragData[0]
        bpData = getattr(data, 'bpData', None)
        if getattr(data, 'item', None):
            itemID = getattr(data.item, 'itemID', None)
            typeID = data.item.typeID
        else:
            typeID = getattr(data, 'typeID', None)
            itemID = getattr(data, 'itemID', None)
        if itemID or typeID:
            categoryID = cfg.invtypes.Get(typeID).categoryID
            if industryCommon.IsBlueprintCategory(categoryID):
                Industry.OpenOrShowBlueprint(itemID, typeID, bpData)
            else:
                raise UserError('ItemNotBlueprint', {'itemname': typeID})

    def OnIndustryDropData(self, dragSource, dragData):
        self.OnDropData(dragSource, dragData)

    def OnIndustryRemoveBlueprint(self):
        """
        Active blueprint removed by user
        """
        self.jobData = None
        self.OnNewJobData()

    def OnIndustryJob(self, jobID, ownerID, blueprintID, installerID, status,
                      successfulRuns):
        """
        Notification if a job is modified in anyway.
        """
        if self.destroyed:
            return
        if self.jobData and self.jobData.jobID == jobID:
            if status == industry.STATUS_CANCELLED:
                self.jobData = None
            else:
                self.jobData.status = status
                self.jobData.successfulRuns = successfulRuns
            self.OnNewJobData()
        elif self.jobData and self.jobData.blueprintID == blueprintID:
            self.jobData = sm.GetService('industrySvc').GetJobByID(jobID)
            self.OnNewJobData()
        if status in (industry.STATUS_INSTALLED, industry.STATUS_READY):
            if self.tabs.GetSelectedIdx() != TAB_JOBS:
                self.tabs.BlinkPanelByName(
                    localization.GetByLabel('UI/Industry/Jobs'))
        if status == industry.STATUS_INSTALLED:
            if self.tabs.GetSelectedIdx() == TAB_BLUEPRINTS:
                self.browserBlueprints.SetFocus()

    def OnBlueprintReload(self, ownerID):
        """
        If a blueprint changes relating to our current job, just reload.
        """
        if self.jobData and self.jobData.ownerID == ownerID:
            self.Reload()

    def OnFacilityReload(self, facilityID):
        """
        If a facility changes relating to our current job, just reload.
        """
        if self.jobData and self.jobData.facilityID == facilityID:
            self.Reload(force=True)

    def Reload(self, force=False):
        """
        Whatever the industry window is currently displaying at the top, reload all the data and redraw.
        """
        try:
            jobData = self.jobData
            if jobData:
                if force:
                    self.jobData = None
                if jobData.jobID:
                    self.ShowJob(jobData.jobID)
                else:
                    self.ShowBlueprint(
                        blueprintID=jobData.blueprint.blueprintID,
                        blueprintTypeID=jobData.blueprint.blueprintTypeID,
                        activityID=jobData.activityID,
                        bpData=jobData.blueprint)
        except UserError:
            self.OnIndustryRemoveBlueprint()
Example #2
0
class ShipUI(LayerCore):
    __notifyevents__ = ['OnShipScanCompleted',
     'OnJamStart',
     'OnJamEnd',
     'OnCargoScanComplete',
     'DoBallRemove',
     'OnSetDevice',
     'OnAssumeStructureControl',
     'OnRelinquishStructureControl',
     'OnUIRefresh',
     'OnUIScalingChange',
     'ProcessPendingOverloadUpdate',
     'OnSafeLogoffTimerStarted',
     'OnSafeLogoffActivated',
     'OnSafeLogoffAborted',
     'OnSafeLogoffFailed',
     'DoBallsRemove',
     'OnSetCameraOffset',
     'ProcessShipEffect',
     'OnStateChange']

    def ApplyAttributes(self, attributes):
        LayerCore.ApplyAttributes(self, attributes)
        self.setupShipTasklet = None
        self.updateTasklet = None
        self.controller = ActiveShipController()
        self.controller.on_new_itemID.connect(self.OnShipChanged)
        self.ResetSelf()

    def Close(self):
        LayerCore.Close(self)
        self.controller.Close()

    def OnSetCameraOffset(self, cameraOffset):
        self.UpdatePosition()

    def OnSetDevice(self):
        self.UpdatePosition()

    def OnUIScalingChange(self, *args):
        self.OnUIRefresh()

    def OnUIRefresh(self):
        self.CloseView(recreate=False)
        self.OpenView()

    @telemetry.ZONE_METHOD
    def ResetSelf(self):
        self.sr.safetyButton = None
        self.fighterHudBinding = None
        self.sr.selectedcateg = 0
        self.sr.pendingreloads = []
        self.sr.reloadsByID = {}
        self.sr.rampTimers = {}
        self.shipuiReady = False
        self.initing = None
        self.jammers = {}
        self.assumingdelay = None
        if self.updateTasklet is not None:
            self.updateTasklet.kill()
        self.updateTasklet = None
        if self.setupShipTasklet is not None:
            self.setupShipTasklet.kill()
        self.setupShipTasklet = None
        self.logoffTimer = None
        self.Flush()

    def CheckPendingReloads(self):
        if self.sr.pendingreloads:
            rl = self.sr.pendingreloads[0]
            while rl in self.sr.pendingreloads:
                self.sr.pendingreloads.remove(rl)

            module = self.GetModule(rl)
            if module:
                module.AutoReload()

    def CheckSession(self, change):
        if sm.GetService('autoPilot').GetState():
            self.OnAutoPilotOn()
        else:
            self.OnAutoPilotOff()

    @telemetry.ZONE_METHOD
    def UpdatePosition(self):
        cameraOffset = sm.GetService('sceneManager').GetCameraOffset()
        halfWidth = uicore.desktop.width / 2
        baseOffset = -cameraOffset * halfWidth
        wndLeft = settings.char.windows.Get('shipuialignleftoffset', 0)
        maxRight, minLeft = self.GetShipuiOffsetMinMax()
        self.hudContainer.left = min(maxRight, max(minLeft, baseOffset + wndLeft))
        self.ewarCont.left = self.hudContainer.left
        if IsShipHudTopAligned():
            self.hudContainer.SetAlign(uiconst.CENTERTOP)
            self.ewarCont.SetAlign(uiconst.CENTERTOP)
            self.sr.indicationContainer.top = self.hudContainer.height + self.ewarCont.height
        else:
            self.hudContainer.SetAlign(uiconst.CENTERBOTTOM)
            self.ewarCont.SetAlign(uiconst.CENTERBOTTOM)
            self.sr.indicationContainer.top = -(self.ewarCont.height + self.sr.indicationContainer.height)
        if self.IsFightersDetached():
            left, top = settings.char.ui.Get('fightersDetachedPosition', (0, 0))
            buttonWidth = 32
            left = min(left, uicore.desktop.width - buttonWidth)
            top = min(top, uicore.desktop.height - self.fighterCont.height)
            self.fighterCont.left = left
            self.fighterCont.top = top
            settings.char.ui.Set('fightersDetachedPosition', (left, top))
        self.AlignFighters()
        self.sr.shipAlertContainer.UpdatePosition()

    def MakeFighterHudBinding(self):
        cs = uicore.uilib.bracketCurveSet
        self.fighterHudBinding = trinity.CreatePythonBinding(cs, self.compass, 'absoluteRight', self.fighterCont, 'left')

    def RemoveFighterHudBinding(self):
        if self.fighterHudBinding:
            cs = uicore.uilib.bracketCurveSet
            cs.bindings.fremove(self.fighterHudBinding)
            self.fighterHudBinding = None

    def OnShipMouseDown(self, wnd, btn, *args):
        if btn != 0:
            return
        self.dragging = True
        if not self.hudContainer:
            return
        self.grab = [uicore.uilib.x, self.hudContainer.left]
        uthread.new(self.BeginDrag)

    def GetShipuiOffsetMinMax(self, *args):
        magicNumber = 275
        if self.CheckShipHasFighterBay():
            magicNumber = 300
        sidePanelsLeft, sidePanelsRight = uicore.layer.sidepanels.GetSideOffset()
        maxRight = uicore.desktop.width / 2 - self.slotsContainer.width / 2 - magicNumber - sidePanelsRight
        minLeft = -(uicore.desktop.width / 2 - 180) + sidePanelsLeft
        return (maxRight, minLeft)

    def OnToggleShipSelected(self, *args):
        if not self.CheckShipHasFighterBay():
            return
        if not self.IsFightersShown():
            self.DeselectShip()
            return
        x, y = self.grab
        currentX, currentY = uicore.uilib.x, self.hudContainer.left
        if x != currentX or y != currentY:
            return
        if uicore.uilib.Key(uiconst.VK_CONTROL):
            if movementFunctions.IsSelectedForNavigation(session.shipid):
                self.DeselectShip()
            else:
                self.SelectShip()
        else:
            self.SelectShip()
            self.fighterCont.ClearSelection()

    def SelectShip(self):
        movementFunctions.SelectForNavigation(session.shipid)

    def DeselectShip(self):
        movementFunctions.DeselectForNavigation(session.shipid)

    def OnStateChange(self, itemID, flag, flagState, *args):
        if not self.CheckShipHasFighterBay():
            return
        if flag == states.selectedForNavigation and itemID == session.shipid:
            if flagState:
                self.ShowSelectionHilite()
            else:
                self.HideSelectionHilite()

    def ShowSelectionHilite(self):
        if self.shipSelectHilight.display:
            return
        self.shipSelectHilight.display = True
        self.ringSprite.opacity = 0.2
        self.bracketSprite.opacity = 3.0
        uicore.animations.FadeTo(self.ringSprite, self.ringSprite.opacity, 1.0, duration=0.2)
        uicore.animations.FadeTo(self.bracketSprite, self.bracketSprite.opacity, 1.0, duration=0.2)

    def HideSelectionHilite(self):
        self.shipSelectHilight.display = False

    def OnShipMouseUp(self, wnd, btn, *args):
        if btn != 0:
            return
        sm.StartService('ui').ForceCursorUpdate()
        self.dragging = False

    def BeginDrag(self, *args):
        cameraOffset = sm.GetService('sceneManager').GetCameraOffset()
        halfWidth = uicore.desktop.width / 2
        baseOffset = -cameraOffset * halfWidth
        while not self.hudContainer.destroyed and getattr(self, 'dragging', 0):
            uicore.uilib.SetCursor(uiconst.UICURSOR_DIVIDERADJUST)
            maxRight, minLeft = self.GetShipuiOffsetMinMax()
            grabMouseDiff = uicore.uilib.x - self.grab[0]
            combinedOffset = min(maxRight, max(minLeft, self.grab[1] + grabMouseDiff))
            dragOffset = combinedOffset - baseOffset
            if -8 <= dragOffset <= 8:
                settings.char.windows.Set('shipuialignleftoffset', 0)
                self.hudContainer.left = baseOffset
            else:
                self.hudContainer.left = combinedOffset
                settings.char.windows.Set('shipuialignleftoffset', dragOffset)
            self.ewarCont.left = self.hudContainer.left
            blue.pyos.synchro.SleepWallclock(1)

    def ConstructOverlayContainer(self):
        self.toggleLeftBtn = Sprite(parent=self.overlayContainer, name='expandBtnLeft', pos=(56, 122, 28, 28), align=uiconst.TOPLEFT, state=uiconst.UI_NORMAL, texturePath='res:/UI/Texture/classes/ShipUI/expandBtnLeft.png')
        self.toggleLeftBtn.OnClick = self.ToggleHudButtons
        hudButtonsExpanded = settings.user.ui.Get('hudButtonsExpanded', 1)
        self.toggleLeftBtn.hint = [GetByLabel('UI/Inflight/ShowButtons'), GetByLabel('UI/Inflight/HideButtons')][hudButtonsExpanded]
        self.optionsCont = Container(parent=self.overlayContainer, name='optionsCont', pos=(190, 190, 16, 16), align=uiconst.TOPLEFT, state=uiconst.UI_PICKCHILDREN)
        self.moduleToggleCont = Container(parent=self.overlayContainer, name='moduleToggleCont', pos=(206, 170, 24, 24), align=uiconst.TOPLEFT, state=uiconst.UI_PICKCHILDREN)
        if not IsControllingStructure():
            self.stopButton = StopButton(parent=self.overlayContainer, align=uiconst.TOPLEFT, controller=self.controller, left=75, top=155)
            self.maxspeedButton = MaxSpeedButton(parent=self.overlayContainer, align=uiconst.TOPLEFT, controller=self.controller, left=168, top=155)

    @telemetry.ZONE_METHOD
    def OnOpenView(self):
        self.ResetSelf()
        self.state = uiconst.UI_HIDDEN
        self.hudContainer = Container(name='hudContainer', parent=self, controller=self.controller, align=uiconst.CENTERBOTTOM, width=SHIP_UI_WIDTH, height=SHIP_UI_HEIGHT)
        self.overlayContainer = Container(parent=self.hudContainer, name='overlayContainer', pos=(0, 0, 256, 256), align=uiconst.CENTER, state=uiconst.UI_PICKCHILDREN, idx=0)
        self.ConstructOverlayContainer()
        if IsControllingStructure():
            shipShape = StructureHUDShape(parent=self.hudContainer, align=uiconst.CENTER)
        else:
            shipShape = HUDShape(parent=self.hudContainer, align=uiconst.CENTER)
        self.shipuiMainShape = shipShape.shipuiMainShape
        self.capacitorContainer = CapacitorContainer(parent=self.hudContainer, align=uiconst.CENTER, top=-1, controller=self.controller)
        self.capacitorContainer.OnMouseDown = (self.OnShipMouseDown, self.capacitorContainer)
        self.capacitorContainer.OnMouseUp = (self.OnShipMouseUp, self.capacitorContainer)
        self.capacitorContainer.OnClick = self.OnToggleShipSelected
        heatPicker = Container(name='heatPicker', parent=self.hudContainer, align=uiconst.CENTER, width=160, height=160, pickRadius=43, state=uiconst.UI_NORMAL)
        self.heatGauges = HeatGauges(parent=heatPicker, align=uiconst.CENTERTOP, controller=self.controller)
        self.hpGauges = HPGauges(name='healthGauges', parent=self.hudContainer, align=uiconst.CENTER, pos=(0, -37, 148, 74), controller=self.controller)
        if IsControllingStructure():
            ReleaseControlBtn(parent=self.hudContainer, top=29, align=uiconst.CENTERBOTTOM, itemID=self.controller.GetItemID(), func=sm.GetService('structureControl').Alight)
        else:
            self.speedGauge = SpeedGauge(parent=self.hudContainer, top=29, align=uiconst.CENTERBOTTOM, controller=self.controller)
        self.compass = Compass(parent=self.hudContainer, pickRadius=-1)
        self.shipSelectHilight = Container(name='navSelectHilight', parent=self.compass, align=uiconst.CENTER, state=uiconst.UI_DISABLED, width=206, height=206)
        self.ringSprite = Sprite(bgParent=self.shipSelectHilight, texturePath='res:/UI/Texture/classes/ShipUI/Fighters/selectionRingLarge.png')
        self.bracketSprite = Sprite(bgParent=self.shipSelectHilight, texturePath='res:/UI/Texture/classes/ShipUI/Fighters/selectionBracketLarge.png')
        self.shipSelectHilight.display = False
        self.slotsContainer = SlotsContainer(parent=self.hudContainer, pos=(SLOTS_CONTAINER_LEFT,
         SLOTS_CONTAINER_TOP,
         SLOTS_CONTAINER_WIDTH,
         SLOTS_CONTAINER_HEIGHT), align=uiconst.CENTERLEFT, state=uiconst.UI_PICKCHILDREN, controller=self.controller)
        self.stanceButtons = StanceButtons(parent=self.hudContainer, pos=(SLOTS_CONTAINER_LEFT + 8,
         1,
         40,
         120), name='stanceButtons', align=uiconst.CENTERLEFT, state=uiconst.UI_PICKCHILDREN, buttonSize=36)
        self.hudButtons = HudButtonsCont(parent=self.hudContainer, align=uiconst.CENTERRIGHT, left=690, top=15)
        self.ewarCont = EwarContainer(parent=self, align=uiconst.CENTERBOTTOM, top=SHIP_UI_HEIGHT, height=EWAR_CONTAINER_HEIGHT, width=EWAR_CONTAINER_WIDTH)
        self.sr.shipAlertContainer = ShipAlertContainer(parent=self.hudContainer)
        self.sr.indicationContainer = Container(parent=self.hudContainer, name='indicationContainer', align=uiconst.CENTERTOP, pos=(0, 0, 400, 50))
        self.sr.safetyButton = SafetyButton(parent=self.overlayContainer, left=40, top=28)
        self.ConstructReadoutCont()
        self.settingsMenu = UtilMenu(menuAlign=uiconst.BOTTOMLEFT, parent=self.optionsCont, align=uiconst.TOPLEFT, GetUtilMenu=self.GetHUDOptionMenu, pos=(0, 0, 16, 16), texturePath='res:/UI/Texture/Icons/73_16_50.png', hint=GetByLabel('UI/Inflight/Options'))
        self.moduleToggleBtn = ButtonIcon(name='moduleToggleBtn', parent=self.moduleToggleCont, align=uiconst.TOPLEFT, width=24, height=24, iconSize=24, texturePath='res:/UI/Texture/classes/ShipUI/Fighters/toggleModules_Up.png', downTexture='res:/UI/Texture/classes/ShipUI/Fighters/toggleModules_Down.png', hoverTexture='res:/UI/Texture/classes/ShipUI/Fighters/toggleModules_Over.png', func=self.OnToggleHudModules)
        self.moduleToggleBtn.display = False
        self.DrawFighters()
        self.hudContainer.state = uiconst.UI_PICKCHILDREN
        self.UpdatePosition()
        self.shipuiReady = True
        self.SetupShip()

    def DrawFighters(self):
        if hasattr(self, 'fighterCont'):
            self.fighterCont.Close()
        self.fighterCont = SquadronsUI(name='fighters', parent=self, state=uiconst.UI_PICKCHILDREN, parentFunc=self.OnToggleFightersDetached)
        self.AlignFighters()
        if self.IsFightersDetached():
            left, top = settings.char.ui.Get('fightersDetachedPosition', (uicore.desktop.width / 2, uicore.desktop.height / 2 - 60))
            self.fighterCont.left = left
            self.fighterCont.top = top
            self.slotsContainer.display = True
            self.moduleToggleBtn.Disable()
        self.SetFighterButtonsHint()
        self.fighterCont.KeepSelection()

    def SetFighterButtonsHint(self):
        if self.IsFightersDetached():
            self.fighterCont.fighterToggleBtn.hint = GetByLabel('UI/Inflight/HUDOptions/ClickToAttach')
            self.moduleToggleBtn.hint = ''
        else:
            self.fighterCont.fighterToggleBtn.hint = GetByLabel('UI/Inflight/HUDOptions/DragToDetach')
            self.moduleToggleBtn.hint = GetByLabel('UI/Inflight/HUDOptions/ClickToToggle')

    def CheckShipHasFighterBay(self):
        shipTypeID = self.controller.GetTypeID()
        godmaSM = sm.GetService('godma').GetStateManager()
        return godmaSM.GetType(shipTypeID).fighterCapacity > 0

    def OptionsBtnMouseEnter(self, *args):
        self.options.SetAlpha(1.0)

    def OptionsBtnMouseExit(self, *args):
        self.options.SetAlpha(0.8)

    def CheckControl(self):
        control = sm.GetService('pwn').GetCurrentControl()
        if control:
            self.OnAssumeStructureControl()

    def SetButtonState(self):
        if settings.user.ui.Get('hudButtonsExpanded', 1):
            self.hudButtons.state = uiconst.UI_PICKCHILDREN
            if IsControllingStructure():
                self.hudButtons.autopilotBtn.Disable()
            else:
                self.hudButtons.autopilotBtn.Enable()
        else:
            self.hudButtons.state = uiconst.UI_HIDDEN

    def ConstructReadoutLabel(self, refName):
        cont = ContainerAutoSize(name=refName, parent=self.readoutCont, align=uiconst.TOTOP)
        label = EveLabelSmall(parent=cont, left=2, state=uiconst.UI_DISABLED, align=uiconst.TOPRIGHT)
        Line(parent=cont, top=6, width=-130, height=1, align=uiconst.TOPRIGHT)
        Line(parent=cont, top=6, width=-130, height=1, align=uiconst.TOPRIGHT, color=(0.1, 0.1, 0.1, 0.5))
        return label

    @telemetry.ZONE_METHOD
    def ConstructReadoutCont(self):
        self.readoutCont = ContainerAutoSize(name='readoutCont', parent=self.hudContainer, pos=(278, 22, 200, 0), align=uiconst.TOPLEFT, state=uiconst.UI_HIDDEN)
        self.readoutShieldLabel = self.ConstructReadoutLabel('shield')
        self.readoutArmorLabel = self.ConstructReadoutLabel('armor')
        self.readoutStructureLabel = self.ConstructReadoutLabel('structure')

    def OnAssumeStructureControl(self, *args):
        now = blue.os.GetSimTime()
        self.assumingdelay = now
        uthread.new(self.DelayedOnAssumeStructureControl, now)

    def DelayedOnAssumeStructureControl(self, issueTime):
        blue.pyos.synchro.SleepSim(250)
        if self.assumingdelay is None:
            return
        issuedAt = self.assumingdelay
        if issuedAt != issueTime:
            return
        self.assumingdelay = None
        self.ShowStructureControl()

    def ShowStructureControl(self, *args):
        if self.controller.IsControllingTurret():
            self.initing = 1
            self.slotsContainer.InitSlots()
            self.hudButtons.InitButtons()
            self.initing = 0

    def OnRelinquishStructureControl(self, *args):
        self.SetupShip()

    def UpdateButtonsForShip(self):
        itemID = self.controller.GetItemID()
        typeID = self.controller.GetTypeID()
        if self.stanceButtons.HasStances():
            self._HideStancePanel()
        self.stanceButtons.UpdateButtonsForShip(itemID, typeID)
        if self.stanceButtons.HasStances():
            self._ShowStancePanel()

    def _ShowStancePanel(self):
        self.slotsContainer.left = SLOTS_CONTAINER_LEFT + 44
        self.stanceButtons.Show()

    def _HideStancePanel(self):
        self.slotsContainer.left = SLOTS_CONTAINER_LEFT
        self.stanceButtons.Hide()

    def GetHUDOptionMenu(self, menuParent):
        showPassive = settings.user.ui.Get('showPassiveModules', 1)
        text = GetByLabel('UI/Inflight/HUDOptions/DisplayPassiveModules')
        menuParent.AddCheckBox(text=text, checked=showPassive, callback=self.ToggleShowPassive)
        showEmpty = settings.user.ui.Get('showEmptySlots', 0)
        text = GetByLabel('UI/Inflight/HUDOptions/DisplayEmptySlots')
        menuParent.AddCheckBox(text=text, checked=showEmpty, callback=self.ToggleShowEmpty)
        showReadout = settings.user.ui.Get('showReadout', 0)
        text = GetByLabel('UI/Inflight/HUDOptions/DisplayReadout')
        menuParent.AddCheckBox(text=text, checked=showReadout, callback=self.ToggleReadout)
        readoutType = settings.user.ui.Get('readoutType', 1)
        text = GetByLabel('UI/Inflight/HUDOptions/DisplayReadoutAsPercentage')
        if showReadout:
            callback = self.ToggleReadoutType
        else:
            callback = None
        menuParent.AddCheckBox(text=text, checked=readoutType, callback=callback)
        showZoomBtns = settings.user.ui.Get('showZoomBtns', 0)
        text = GetByLabel('UI/Inflight/HUDOptions/DisplayZoomButtons')
        menuParent.AddCheckBox(text=text, checked=showZoomBtns, callback=self.ToggleShowZoomBtns)
        showTooltips = settings.user.ui.Get('showModuleTooltips', 1)
        text = GetByLabel('UI/Inflight/HUDOptions/DisplayModuleTooltips')
        menuParent.AddCheckBox(text=text, checked=showTooltips, callback=self.ToggleShowModuleTooltips)
        lockModules = settings.user.ui.Get('lockModules', 0)
        text = GetByLabel('UI/Inflight/HUDOptions/LockModulesInPlace')
        menuParent.AddCheckBox(text=text, checked=lockModules, callback=self.ToggleLockModules)
        menuParent.AddCheckBox(text=GetByLabel('UI/Inflight/HUDOptions/BlinkCargo'), checked=self.GetCargoBlinkValue(), callback=self.ToggleBlinkCargo)
        lockOverload = settings.user.ui.Get('lockOverload', 0)
        text = GetByLabel('UI/Inflight/HUDOptions/LockOverloadState')
        menuParent.AddCheckBox(text=text, checked=lockOverload, callback=self.ToggleOverloadLock)
        text = GetByLabel('UI/Inflight/HUDOptions/AlignHUDToTop')
        cb = menuParent.AddCheckBox(text=text, checked=IsShipHudTopAligned(), callback=self.ToggleAlign)
        cb.isToggleEntry = False
        menuParent.AddDivider()
        text = GetByLabel('UI/Inflight/NotifySettingsWindow/DamageAlertSettings')
        iconPath = 'res:/UI/Texture/classes/UtilMenu/BulletIcon.png'
        menuParent.AddIconEntry(icon=iconPath, text=text, callback=self.ShowNotifySettingsWindow)
        if sm.GetService('logger').IsInDragMode():
            text = GetByLabel('UI/Accessories/Log/ExitMessageMovingMode')
            enterArgs = False
        else:
            text = GetByLabel('UI/Accessories/Log/EnterMessageMovingMode')
            enterArgs = True
        menuParent.AddIconEntry(icon='res:/UI/Texture/classes/UtilMenu/BulletIcon.png', text=text, callback=(sm.GetService('logger').MoveNotifications, enterArgs))

    def ShowNotifySettingsWindow(self):
        NotifySettingsWindow.Open()

    def ToggleAlign(self):
        SetShipHudTopAligned(not IsShipHudTopAligned())
        self.UpdatePosition()
        for each in uicore.layer.abovemain.children[:]:
            if each.name == 'message':
                each.Close()
                break

        msg = getattr(uicore.layer.target, 'message', None)
        if msg:
            msg.Close()

    def CheckShowReadoutCont(self):
        if settings.user.ui.Get('showReadout', 0):
            self.readoutCont.state = uiconst.UI_DISABLED
            self.hudButtons.top = 30
        else:
            self.readoutCont.state = uiconst.UI_HIDDEN
            self.hudButtons.top = 15

    def ToggleReadout(self):
        current = not settings.user.ui.Get('showReadout', 0)
        settings.user.ui.Set('showReadout', current)
        self.CheckShowReadoutCont()

    def GetCargoBlinkValue(self):
        return settings.user.ui.Get('BlinkCargoHudIcon', True)

    def ToggleBlinkCargo(self):
        settings.user.ui.Set('BlinkCargoHudIcon', not self.GetCargoBlinkValue())

    def ToggleReadoutType(self):
        current = settings.user.ui.Get('readoutType', 1)
        settings.user.ui.Set('readoutType', not current)

    def ToggleShowZoomBtns(self):
        settings.user.ui.Set('showZoomBtns', not settings.user.ui.Get('showZoomBtns', 0))
        self.hudButtons.InitButtons()

    def ToggleLockModules(self):
        settings.user.ui.Set('lockModules', not settings.user.ui.Get('lockModules', 0))
        self.slotsContainer.CheckGroupAllButton()

    def ToggleOverloadLock(self):
        settings.user.ui.Set('lockOverload', not settings.user.ui.Get('lockOverload', 0))

    def ToggleShowModuleTooltips(self):
        settings.user.ui.Set('showModuleTooltips', not settings.user.ui.Get('showModuleTooltips', 1))

    def ToggleHudButtons(self):
        isExpanded = self.hudButtons.state == uiconst.UI_PICKCHILDREN
        if isExpanded:
            self.hudButtons.state = uiconst.UI_HIDDEN
        else:
            self.hudButtons.state = uiconst.UI_PICKCHILDREN
        settings.user.ui.Set('hudButtonsExpanded', not isExpanded)
        sm.GetService('ui').StopBlink(self.toggleLeftBtn)
        self.CheckExpandBtns()

    def OnToggleHudModules(self, *args):
        settings.user.ui.Set('displayFighterUI', not settings.user.ui.Get('displayFighterUI', False))
        self.ShowHideFighters()

    def OnToggleFightersDetached(self, *args):
        isDetached = self.IsFightersDetached()
        settings.user.ui.Set('detachFighterUI', not isDetached)
        if isDetached:
            self.AttachHudModules()
        else:
            self.DetachHudModules()

    def AttachHudModules(self):
        self.moduleToggleBtn.Enable()
        self.AlignFighters()
        self.fighterCont.left = 0
        self.fighterCont.top = 10
        self.MakeFighterHudBinding()
        self.ShowHideFighters()
        self.SetFighterButtonsHint()

    def DetachHudModules(self):
        self.moduleToggleBtn.Disable()
        self.slotsContainer.display = True
        self.RemoveFighterHudBinding()
        self.DrawFighters()

    def InitFighters(self):
        if not self.IsFightersDetached():
            self.MakeFighterHudBinding()
            self.ShowHideFighters()
        else:
            self.DetachHudModules()
            self.slotsContainer.display = True

    def ShowHideFighters(self):
        displayFighters = self.IsFightersShown()
        isDetached = self.IsFightersDetached()
        if self.CheckShipHasFighterBay():
            if isDetached:
                self.fighterCont.display = True
                self.slotsContainer.display = True
                return
            if displayFighters == True:
                self.fighterCont.display = True
                self.slotsContainer.display = False
                return
        self.fighterCont.ClearSelection()
        self.fighterCont.display = False
        self.slotsContainer.display = True
        self.DeselectShip()

    def AlignFighters(self):
        if self.IsFightersDetached():
            self.fighterCont.SetAlign(uiconst.TOPLEFT)
        elif IsShipHudTopAligned():
            self.fighterCont.SetAlign(uiconst.TOTOP)
        else:
            self.fighterCont.SetAlign(uiconst.TOBOTTOM)
            self.fighterCont.top = 10

    def IsFightersDetached(self):
        return settings.user.ui.Get('detachFighterUI', False)

    def IsFightersShown(self):
        return settings.user.ui.Get('displayFighterUI', False)

    def CheckExpandBtns(self):
        on = settings.user.ui.Get('hudButtonsExpanded', 1)
        if on:
            self.toggleLeftBtn.LoadTexture('res:/UI/Texture/classes/ShipUI/expandBtnRight.png')
        else:
            self.toggleLeftBtn.LoadTexture('res:/UI/Texture/classes/ShipUI/expandBtnLeft.png')
        self.toggleLeftBtn.hint = [GetByLabel('UI/Inflight/ShowButtons'), GetByLabel('UI/Inflight/HideButtons')][on]

    def AddBookmarks(self, bookmarkIDs):
        isMove = not uicore.uilib.Key(uiconst.VK_SHIFT)
        sm.GetService('invCache').GetInventoryFromId(session.shipid).AddBookmarks(bookmarkIDs, const.flagCargo, isMove)

    def Scanner(self, button):
        self.expandTimer = None
        uicore.layer.menu.Flush()
        radialMenu = RadialMenuScanner(name='radialMenu', parent=uicore.layer.menu, state=uiconst.UI_NORMAL, align=uiconst.TOPLEFT, anchorObject=button)
        uicore.layer.menu.radialMenu = radialMenu
        uicore.uilib.SetMouseCapture(radialMenu)

    def BlinkButton(self, key):
        self.slotsContainer.BlinkButton(key)

    def ChangeOpacityForRange(self, currentRange, *args):
        if getattr(self, 'slotContainer', None):
            self.slotsContainer.ChangeOpacityForRange(self, currentRange)

    def ResetModuleButtonOpacity(self, *args):
        if getattr(self, 'slotContainer', None):
            self.slotsContainer.ResetModuleButtonOpacity()

    def ToggleRackOverload(self, slotName):
        self.slotsContainer.ToggleRackOverload(slotName)

    def ProcessPendingOverloadUpdate(self, moduleIDs):
        self.slotsContainer.ProcessPendingOverloadUpdate(moduleIDs)

    def ResetSwapMode(self):
        self.slotsContainer.ResetSwapMode()

    def StartDragMode(self, itemID, typeID):
        self.slotsContainer.StartDragMode(itemID, typeID)

    def GetPosFromFlag(self, slotFlag):
        return self.slotsContainer.GetPosFromFlag(slotFlag)

    def GetSlotByName(self, name):
        return self.slotsContainer.FindChild(name)

    def ChangeSlots(self, toFlag, fromFlag):
        self.slotsContainer.ChangeSlots(toFlag, fromFlag)

    def SwapSlots(self, slotFlag1, slotFlag2):
        self.slotsContainer.SwapSlots(slotFlag1, slotFlag2)

    def LinkWeapons(self, master, slave, slotFlag1, slotFlag2, merge = False):
        self.slotsContainer.LinkWeapons(master, slave, slotFlag1, slotFlag2, merge)

    def GetModuleType(self, flag):
        return self.slotsContainer.GetModuleType(flag)

    def GetModuleFromID(self, moduleID):
        return self.slotsContainer.GetModuleFromID(moduleID)

    def ToggleShowEmpty(self):
        self.slotsContainer.ToggleShowEmpty()

    def ToggleShowPassive(self):
        self.slotsContainer.ToggleShowPassive()

    def GetModuleForFKey(self, key):
        return self.slotsContainer.GetModuleForFKey(key)

    def GetModule(self, moduleID):
        return self.slotsContainer.GetModule(moduleID)

    def OnF(self, sidx, gidx):
        if not self.CheckShipHasFighterBay():
            self.slotsContainer.OnF(sidx, gidx)
            return
        shipIsSelected, fightersSelected = movementFunctions.GetSelectedShipAndFighters()
        if self.IsFightersDetached():
            moduleIsActive = self.IsModuleActiveForFKey(sidx, gidx)
            isAllAbilitiesActiveOrInCooldown = GetShipFighterState().IsAllAbilitiesInSlotActiveOrInCooldown(sidx)
            if shipIsSelected:
                if isAllAbilitiesActiveOrInCooldown:
                    if moduleIsActive is not None:
                        self.slotsContainer.OnF(sidx, gidx)
                    if moduleIsActive is None or moduleIsActive == True:
                        self.fighterCont.OnF(sidx)
                else:
                    self.fighterCont.OnF(sidx)
                    if moduleIsActive == False:
                        self.slotsContainer.OnF(sidx, gidx)
            else:
                self.fighterCont.OnF(sidx)
        elif self.IsFightersShown():
            self.fighterCont.OnF(sidx)
        else:
            self.slotsContainer.OnF(sidx, gidx)

    def GetModuleDefaultEffect(self, sidx, gidx):
        slot = self.slotsContainer.slotsByOrder.get((gidx, sidx), None)
        if not slot:
            return
        if not slot.sr.module:
            return
        if slot.sr.module.state != uiconst.UI_NORMAL:
            return
        if slot.sr.module.def_effect is None:
            return
        return slot.sr.module.def_effect

    def IsModuleActiveForFKey(self, sidx, gidx):
        defaultEffect = self.GetModuleDefaultEffect(sidx, gidx)
        if defaultEffect:
            return defaultEffect.isActive

    def OnFKeyOverload(self, sidx, gidx):
        self.slotsContainer.OnFKeyOverload(sidx, gidx)

    def OnReloadAmmo(self):
        self.slotsContainer.OnReloadAmmo()

    def OnCloseView(self):
        self.ResetSelf()
        settings.user.ui.Set('selected_shipuicateg', self.sr.selectedcateg)
        t = uthread.new(sm.GetService('space').OnShipUIReset)
        t.context = 'ShipUI::OnShipUIReset'

    @telemetry.ZONE_METHOD
    def DoBallsRemove(self, pythonBalls, isRelease):
        if isRelease:
            self.UnhookBall()
            self.jammers = {}
            return
        for ball, slimItem, terminal in pythonBalls:
            self.DoBallRemove(ball, slimItem, terminal)

        if isRelease:
            self.compass.RemoveAll()

    def DoBallRemove(self, ball, slimItem, terminal):
        if ball is None:
            return
        log.LogInfo('DoBallRemove::shipui', ball.id)
        if self.controller.GetBall() is not None and ball.id == self.controller.GetBall().id:
            self.UnhookBall()
        uthread.new(self.UpdateJammersAfterBallRemoval, ball.id)

    def UpdateJammersAfterBallRemoval(self, ballID):
        jams = self.jammers.keys()
        for jammingType in jams:
            jam = self.jammers[jammingType]
            for id in jam.keys():
                sourceBallID, moduleID, targetBallID = id
                if ballID == sourceBallID:
                    del self.jammers[jammingType][id]

    def ProcessShipEffect(self, godmaStm, effectState):
        if effectState.error is not None:
            uthread.new(uicore.Message, effectState.error[0], effectState.error[1])

    def OnJamStart(self, sourceBallID, moduleID, targetBallID, jammingType, startTime, duration):
        durationInClient = GetDurationInClient(startTime, duration)
        if durationInClient < 0.0:
            return
        if jammingType not in self.jammers:
            self.jammers[jammingType] = {}
        jammerID = (sourceBallID, moduleID, targetBallID)
        self.jammers[jammingType][jammerID] = (blue.os.GetSimTime(), durationInClient)
        if self.ewarCont and targetBallID == session.shipid:
            self.ewarCont.StartTimer(jammingType, jammerID, durationInClient)

    def OnJamEnd(self, sourceBallID, moduleID, targetBallID, jammingType):
        if jammingType in self.jammers:
            jammerID = (sourceBallID, moduleID, targetBallID)
            if jammerID in self.jammers[jammingType]:
                del self.jammers[jammingType][jammerID]

    def OnShipScanCompleted(self, shipID, capacitorCharge, capacitorCapacity, hardwareList):
        bp = sm.GetService('michelle').GetBallpark()
        if not bp:
            return
        slimItem = bp.slimItems[shipID]
        wndName = GetByLabel('UI/Inflight/ScanWindowName', itemName=GetSlimItemName(slimItem), title=GetByLabel('UI/Inflight/ScanResult'))
        import form
        form.ShipScan.CloseIfOpen(windowID=('shipscan', shipID))
        form.ShipScan.Open(windowID=('shipscan', shipID), caption=wndName, shipID=shipID, results=(capacitorCharge, capacitorCapacity, hardwareList))

    def OnCargoScanComplete(self, shipID, cargoList):
        bp = sm.GetService('michelle').GetBallpark()
        if not bp:
            return
        slimItem = bp.slimItems[shipID]
        windowID = ('cargoscanner', shipID)
        import form
        wnd = form.CargoScan.Open(windowID=windowID, shipID=shipID, cargoList=cargoList)
        if wnd:
            wnd.LoadResult(cargoList)

    def UnhookBall(self):
        self.controller.InvalidateBall()

    def OnShipChanged(self, *args):
        self.SetupShip(animate=True)

    def SetupShip(self, animate = False):
        if self.setupShipTasklet is not None:
            self.setupShipTasklet.kill()
        self.setupShipTasklet = uthread.new(self._SetupShip, animate)

    @telemetry.ZONE_METHOD
    def _SetupShip(self, animate = False):
        if self.destroyed or self.initing or not self.shipuiReady:
            return
        self.initing = True
        try:
            if not self.controller.IsLoaded():
                return
            if not sm.GetService('viewState').IsViewActive('planet') and not (eve.hiddenUIState and 'shipui' in eve.hiddenUIState):
                self.state = uiconst.UI_PICKCHILDREN
            self.ResetUpdateTasklet()
            self.sr.rampTimers = {}
            self.slotsContainer.InitSlots(animate)
            self.hudButtons.InitButtons()
            self.SetButtonState()
            self.CheckExpandBtns()
            self.CheckControl()
            self.UpdateButtonsForShip()
            self.capacitorContainer.InitCapacitor()
            self.DrawFighters()
            self.InitFighters()
            self.ShowHideFighters()
            if self.CheckShipHasFighterBay():
                self.moduleToggleBtn.display = True
            else:
                self.moduleToggleBtn.display = False
                if self.shipSelectHilight.display:
                    self.shipSelectHilight.display = False
            blue.pyos.synchro.SleepWallclock(200)
        finally:
            self.initing = False

    def ResetUpdateTasklet(self):
        if self.updateTasklet:
            self.updateTasklet.kill()
        self.updateTasklet = uthread.new(self.UpdateGauges)

    def SetSpeed(self, speedRatio):
        self.controller.SetSpeed(speedRatio)

    def Hide(self):
        self.state = uiconst.UI_HIDDEN

    def Show(self):
        self.state = uiconst.UI_PICKCHILDREN

    def OnMouseEnter(self, *args):
        uicore.layer.inflight.HideTargetingCursor()

    def GetMenu(self):
        return self.controller.GetMenu()

    @telemetry.ZONE_FUNCTION
    def UpdateGauges(self):
        while not self.destroyed:
            try:
                if self.controller.IsLoaded():
                    self.heatGauges.Update()
                    self.hpGauges.Update()
                    self.UpdateReadouts()
            except Exception as e:
                log.LogException(e)

            blue.synchro.SleepWallclock(500)

    def UpdateReadouts(self):
        structure = self.controller.GetStructureHPPortion()
        armor = self.controller.GetArmorHPPortion()
        shield = self.controller.GetShieldHPPortion()
        self.CheckShowReadoutCont()
        if self.readoutCont.state != uiconst.UI_HIDDEN:
            if settings.user.ui.Get('readoutType', 1):
                self.readoutShieldLabel.text = GetByLabel('UI/Common/Formatting/Percentage', percentage=shield * 100)
                self.readoutArmorLabel.text = GetByLabel('UI/Common/Formatting/Percentage', percentage=armor * 100)
                self.readoutStructureLabel.text = GetByLabel('UI/Common/Formatting/Percentage', percentage=structure * 100)
            else:
                self.readoutShieldLabel.text = GetByLabel('UI/Inflight/GaugeAbsolute', left=self.controller.GetShieldHP(), total=self.controller.GetShieldHPMax())
                self.readoutArmorLabel.text = GetByLabel('UI/Inflight/GaugeAbsolute', left=self.controller.GetArmorHP(), total=self.controller.GetArmorHPMax())
                self.readoutStructureLabel.text = GetByLabel('UI/Inflight/GaugeAbsolute', left=self.controller.GetStructureHP(), total=self.controller.GetStructureHPMax())

    def OnSafeLogoffTimerStarted(self, safeLogoffTime):
        if self.logoffTimer is not None:
            self.logoffTimer.Close()
        self.logoffTimer = SafeLogoffTimer(parent=uicore.layer.abovemain, logoffTime=safeLogoffTime)
        self.logoffTimer.left = sm.GetService('window').GetCameraLeftOffset(self.logoffTimer.width, self.logoffTimer.align, self.logoffTimer.left)

    def OnSafeLogoffActivated(self):
        if self.logoffTimer is not None:
            self.logoffTimer.timer.SetText('0.0')
            self.logoffTimer.timer.SetTextColor(Color.GREEN)
        sm.GetService('clientStatsSvc').OnProcessExit()

    def OnSafeLogoffAborted(self, reasonCode):
        self.AbortSafeLogoffTimer()
        uicore.Message('CustomNotify', {'notify': GetByLabel(reasonCode)})

    def OnSafeLogoffFailed(self, failedConditions):
        self.AbortSafeLogoffTimer()
        uicore.Message('CustomNotify', {'notify': '<br>'.join([GetByLabel('UI/Inflight/SafeLogoff/ConditionsFailedHeader')] + [ GetByLabel(error) for error in failedConditions ])})

    def AbortSafeLogoffTimer(self):
        if self.logoffTimer is not None:
            self.logoffTimer.AbortLogoff()
            self.logoffTimer = None
class SolarSystemViewPanel(DockablePanel):
    __notifyevents__ = [
        'OnBallparkSetState', 'OnTacticalOverlayChange', 'OnSessionChanged',
        'OnSetCameraOffset', 'OnHideUI', 'OnShowUI'
    ]
    default_captionLabelPath = None
    default_caption = None
    default_windowID = DOCKPANELID_SOLARSYSTEMMAP
    default_iconNum = 'res:/UI/Texture/classes/ProbeScanner/solarsystemMapButton.png'
    panelID = default_windowID
    mapView = None
    overlayTools = None
    mapViewID = MAPVIEW_SOLARSYSTEM_ID

    def ApplyAttributes(self, attributes):
        DockablePanel.ApplyAttributes(self, attributes)
        self.showRangeIndicator = sm.GetService(
            'tactical').IsTacticalOverlayActive()
        self.mapView = MapViewSolarSystem(
            parent=self.GetMainArea(),
            showInfobox=False,
            navigationPadding=(0, 0, 0, 0),
            navigationClass=MapViewScannerNavigation,
            mapViewID=self.mapViewID,
            showSolarSystemNebula=False,
            showStarfield=False,
            showDebugInfo=False,
            sceneBlendMode=None,
            stackMarkers=True)
        sceneOptionsContainer = Container(parent=self.toolbarContainer,
                                          align=uiconst.CENTERLEFT,
                                          width=100,
                                          height=32,
                                          left=4,
                                          idx=0)
        from eve.client.script.ui.shared.mapView.mapViewSettings import MapViewMarkersSettingButton
        self.markersSettingButton = MapViewMarkersSettingButton(
            parent=sceneOptionsContainer,
            callback=self.OnMarkersSettingChanged,
            mapViewID=self.mapViewID,
            align=uiconst.TOPLEFT,
            left=2,
            top=2)
        focusSelf = ButtonIcon(
            parent=sceneOptionsContainer,
            pos=(26, 2, 26, 26),
            iconSize=16,
            func=self.OnFocusSelf,
            hint=localization.GetByLabel('UI/Map/FocusCurrentLocation'),
            texturePath='res:/UI/Texture/classes/MapView/focusIcon.png',
            align=uiconst.TOPLEFT)
        focusSelf.tooltipPointer = uiconst.POINT_TOP_1
        self.dScanOptions = ButtonIcon(
            parent=sceneOptionsContainer,
            pos=(50, 2, 26, 26),
            iconSize=16,
            texturePath='res:/UI/Texture/classes/MapView/dScanIcon.png',
            align=uiconst.TOPLEFT)
        self.dScanOptions.tooltipPointer = uiconst.POINT_TOP_1
        self.dScanOptions.LoadTooltipPanel = self.LoadDScanTooltipPanel
        uthread.new(self.LoadSolarSystem)
        if uicore.cmd.IsUIHidden():
            self.OnHideUI()

    def OnShowUI(self):
        self.toolbarContainer.display = True

    def OnHideUI(self):
        if self.IsFullscreen():
            self.toolbarContainer.display = False

    def StartDirectionalScanHandler(self):
        self.mapView.currentSolarsystem.EnableDirectionalScanHandler()
        self.dScanOptions.Enable()

    def StopDirectionalScanHandler(self):
        self.mapView.currentSolarsystem.StopDirectionalScanHandler()
        self.dScanOptions.Disable()

    def GetDirectionalScanHandler(self):
        return self.mapView.currentSolarsystem.directionalScanHandler

    def StartProbeHandler(self):
        self.mapView.currentSolarsystem.EnableProbeHandlerStandalone()

    def StopProbeHandler(self):
        self.mapView.currentSolarsystem.StopProbeHandler()

    def OnFocusSelf(self, *args, **kwds):
        self.mapView.FocusSelf()

    def OnMarkersSettingChanged(self, *args, **kwds):
        self.mapView.OnMapViewSettingChanged(*args, **kwds)

    def OnDockModeChanged(self, *args):
        pass

    def OnTacticalOverlayChange(self):
        visible = sm.GetService('tactical').IsTacticalOverlayActive()
        self.showRangeIndicator = visible
        if visible:
            self.mapView.currentSolarsystem.ShowRangeIndicator()
        else:
            self.mapView.currentSolarsystem.HideRangeIndicator()

    def OnBallparkSetState(self):
        if not self.destroyed:
            uthread.new(self.LoadSolarSystem)

    def OnSetCameraOffset(self, cameraOffset):
        if self.IsFullscreen():
            x = -(cameraOffset * 0.5 - 0.5)
            self.mapView.camera.cameraCenter = (x, 0.5)
        else:
            self.mapView.camera.cameraCenter = (0.5, 0.5)

    def OnSessionChanged(self, isRemote, session, change):
        if 'locationid' in change and not IsSolarSystem(
                change['locationid'][1]):
            uthread.new(self.LoadSolarSystem)

    def LoadSolarSystem(self):
        if self.destroyed:
            return
        self.mapView.LoadSolarSystemDetails(session.solarsystemid2)
        lastloaded = settings.char.ui.Get(
            'solarSystemView_loaded_%s' % self.mapViewID, None)
        settings.char.ui.Set('solarSystemView_loaded_%s' % self.mapViewID,
                             session.solarsystemid2)
        resetCamera = lastloaded != session.solarsystemid2
        if resetCamera:
            self.mapView.FrameSolarSystem()
        self.mapView.sceneContainer.display = True
        self.SetCaption(cfg.evelocations.Get(session.solarsystemid2).name)
        if self.showRangeIndicator:
            self.mapView.currentSolarsystem.ShowRangeIndicator()
        probeScanner = ProbeScannerWindow.GetIfOpen()
        if probeScanner:
            self.StartProbeHandler()
        directionalScanner = DirectionalScanner.GetIfOpen()
        if directionalScanner:
            self.StartDirectionalScanHandler()

    def LoadDScanTooltipPanel(self, tooltipPanel, *args):
        if uicore.uilib.leftbtn:
            return
        tooltipPanel.columns = 2
        tooltipPanel.AddLabelSmall(text=localization.GetByLabel(
            'UI/Inflight/Scanner/DirectionalScan'),
                                   bold=True,
                                   cellPadding=(8, 4, 4, 2),
                                   colSpan=tooltipPanel.columns)
        divider = LineThemeColored(align=uiconst.TOTOP,
                                   state=uiconst.UI_DISABLED,
                                   height=1,
                                   padding=(1, 1, 1, 0),
                                   opacity=0.3)
        tooltipPanel.AddCell(divider,
                             cellPadding=(0, 0, 0, 2),
                             colSpan=tooltipPanel.columns)
        for optionName, optionID, checked in (
            (localization.GetByLabel('UI/Inflight/Scanner/ShowScanCone'),
             'showScanCone', GetScanConeDisplayState() == True),
            (localization.GetByLabel('UI/Inflight/Scanner/AlignWithCamera'),
             'cameraAligned', GetActiveScanMode() == SCANMODE_CAMERA)):
            checkBox = Checkbox(align=uiconst.TOPLEFT,
                                text=optionName,
                                checked=checked,
                                wrapLabel=False,
                                callback=self.OnSettingButtonCheckBoxChange,
                                retval=optionID,
                                prefstype=None)
            tooltipPanel.AddCell(cellObject=checkBox,
                                 colSpan=tooltipPanel.columns,
                                 cellPadding=(5, 0, 5, 0))

        tooltipPanel.AddSpacer(width=2, height=2, colSpan=tooltipPanel.columns)
        tooltipPanel.state = uiconst.UI_NORMAL

    def OnSettingButtonCheckBoxChange(self, checkbox, *args, **kwds):
        optionID = checkbox.data['value']
        enabled = checkbox.GetValue()
        if optionID == 'cameraAligned':
            ToggleScanMode()
        elif optionID == 'showScanCone':
            SetScanConeDisplayState(enabled)

    def CmdZoomInOut(self, zoomDelta):
        if self.mapView:
            self.mapView.camera.ZoomMouseWheelDelta(zoomDelta, immediate=False)