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

probeScannerPalette.py (38948B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\inflight\scannerFiles\probeScannerPalette.py
      2 import blue
      3 import eve.client.script.ui.shared.pointerTool.pointerToolConst as pConst
      4 import eve.common.lib.appConst as appConst
      5 import evetypes
      6 import functools
      7 import gametime
      8 import localization
      9 import probescanning.formations as formations
     10 import trinity
     11 import uthread
     12 import uthread2
     13 import weakref
     14 from carbon.client.script.environment.AudioUtil import PlaySound
     15 from carbon.common.script.sys import service
     16 from carbon.common.script.util.format import FmtDist, FmtAmt
     17 from carbon.common.script.util.timerstuff import AutoTimer
     18 from carbonui import TextColor, uiconst
     19 from carbonui.button.const import HEIGHT_COMPACT
     20 from carbonui.control.buttonIcon import ButtonIcon
     21 from carbonui.control.scrollContainer import ScrollContainer
     22 from carbonui.control.slider import Slider
     23 from carbonui.primitives.container import Container
     24 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     25 from carbonui.primitives.layoutGrid import LayoutGrid
     26 from carbonui.primitives.sprite import Sprite
     27 from carbonui.uianimations import animations
     28 from carbonui.uicore import uicore
     29 from carbonui.window.segment.underlay import WindowSegmentUnderlay
     30 from eve.client.script.ui import eveColor
     31 from eve.client.script.ui.control import eveLabel
     32 from eve.client.script.ui.control.eveLabel import EveLabelMedium, Label
     33 from eve.client.script.ui.control.tooltips import ShortcutHint
     34 from eve.client.script.ui.inflight.scannerFiles.scanResults import ScanResults
     35 from eve.client.script.ui.inflight.scannerFiles.scannerToolsUIComponents import FilterBox, IgnoredBox, ProbeTooltipButtonRow, ProbeTooltipCheckboxRow, FormationButton
     36 from eve.client.script.ui.inflight.scannerFiles.scannerUtil import IsProbeScanPanelEmbedded
     37 from eve.client.script.ui.inflight.scannerfiltereditor import ScannerFilterEditor
     38 from eve.client.script.ui.util.uix import QtyPopup
     39 from eve.common.script.sys.idCheckers import IsAbyssalSpaceSystem, IsVoidSpaceSystem
     40 from eveexceptions import UserError
     41 from fsdBuiltData.common.iconIDs import GetIconFile
     42 from inventorycommon.const import groupSurveyProbe
     43 from localization import GetByLabel
     44 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     45 from probescanning.analyzeButton import AnalyzeButton, AnalyzeButtonController
     46 from probescanning.const import probeStateIdle, probeStateInactive, probeLauncherTypeID
     47 from probescanning.scanBonusController import ScanBonusController
     48 from probescanning.tooltips.scanBonusTooltip import ScanBonusTooltip
     49 from probescanning.tooltips.scanProbeTooltip import ScanProbeTooltip
     50 CORE_SCANNER_PROBE_TYPE_ID = 30013
     51 
     52 def AddFilter(*args):
     53     filterOptions = sm.GetService('scanSvc').GetFilterOptions()
     54     customFilters = [ (filterName, filterID) for filterName, filterID in filterOptions if filterID > 0 ]
     55     if len(customFilters) >= 25:
     56         raise UserError('TooManyFilters')
     57     editor = ScannerFilterEditor.Open()
     58     editor.LoadData(None)
     59 
     60 
     61 def UserErrorIfScanning(action, *args, **kwargs):
     62 
     63     @functools.wraps(action)
     64     def wrapper(*args, **kwargs):
     65         if sm.GetService('scanSvc').IsScanning():
     66             raise UserError('ScanInProgressGeneric')
     67         return action(*args, **kwargs)
     68 
     69     return wrapper
     70 
     71 
     72 class ProbeScannerPalette(Container):
     73     __notifyevents__ = ['OnProbeAdded',
     74      'OnProbeRemoved',
     75      'OnProbeRangeUpdated',
     76      'OnSystemScanFilterChanged',
     77      'OnSystemScanBegun',
     78      'OnSystemScanDone',
     79      'OnNewScannerFilterSet',
     80      'OnProbeStateUpdated',
     81      'OnProbePositionsUpdated',
     82      'OnScannerDisconnected',
     83      'OnRefreshScanResults',
     84      'OnBallparkSetState',
     85      'OnReconnectToProbesAvailable',
     86      'OnModuleFitted',
     87      'OnModuleOnlineChange',
     88      'OnChargeLoadedToModule',
     89      'OnProbeScannerUndocked',
     90      'OnProbeScannerDocked',
     91      'OnSessionChanged']
     92     __disallowanalysisgroups = [groupSurveyProbe]
     93     filteredBoxTooltip = None
     94     isBeingTransformed = False
     95     solarSystemView = None
     96 
     97     def ApplyAttributes(self, attributes):
     98         super(ProbeScannerPalette, self).ApplyAttributes(attributes)
     99         sm.RegisterNotify(self)
    100         self.window = attributes.Get('window', None)
    101         self.updateTimer = None
    102         self._filter_toggle_queue = set()
    103         self.scanSvc = sm.GetService('scanSvc')
    104         self.scanBonusController = ScanBonusController()
    105         self.isAnimatingProbeIcon = False
    106         self.ConstructLayout()
    107         self.UpdateControls()
    108 
    109     def UpdateControls(self):
    110         self.UpdateLabels()
    111         self.LoadProbeIcon()
    112         self.UpdateSizeSlider()
    113         self.ActivateBonusTooltips()
    114         self.CheckButtonStates()
    115         uthread.new(self.LoadResultList)
    116 
    117     def _IsCompactHeaderWindow(self):
    118         return self.window and self.window.compact and not self.window.stacked and not self.window.collapsed
    119 
    120     def Reconstruct(self):
    121         self.Flush()
    122         self.probeStateCont.Flush()
    123         self.ConstructLayout()
    124         self.UpdateControls()
    125 
    126     def ConstructLayout(self):
    127         self.ConstructFilterCont()
    128         self.ConstructBottomCont()
    129         self.ConstructProbeStateCont()
    130         self.ConstructFooter()
    131         self.ConstructScroll()
    132 
    133     def ConstructBottomCont(self):
    134         if self.window is None:
    135             pad_left = pad_right = pad_bottom = 4
    136         else:
    137             pad_left, _, pad_right, pad_bottom = self.window.content_padding
    138         self.bottomContainer = Container(name='BottomContainer', parent=self, align=uiconst.TOBOTTOM, height=64, padTop=pad_bottom)
    139         WindowSegmentUnderlay(bgParent=self.bottomContainer, padding=(-pad_left,
    140          -pad_bottom,
    141          -pad_right,
    142          -pad_bottom))
    143 
    144     def ConstructProbeStateCont(self):
    145         self.probeStateCont = Container(name='probeStateCont', parent=self.bottomContainer, align=uiconst.TOTOP, height=24, padBottom=4)
    146         self.probeInfoContainer = ContainerAutoSize(name='probeInfoContainer', parent=self.probeStateCont, align=uiconst.TOLEFT, state=uiconst.UI_NORMAL, padLeft=4)
    147         iconSize = 28
    148         self.probeSprite = Sprite(name='ProbeSprite', parent=self.probeInfoContainer, align=uiconst.CENTERLEFT, state=uiconst.UI_DISABLED, pos=(1,
    149          0,
    150          iconSize,
    151          iconSize))
    152         self.probesLaunchedLabel = EveLabelMedium(name='ProbesLaunchedLabel', parent=self.probeInfoContainer, align=uiconst.CENTERLEFT, left=iconSize + 4)
    153         self.recoverButton = ButtonIcon(name='RecoverProbesButton', parent=self.probeStateCont, iconSize=16, width=16, padLeft=4, hint=GetByLabel('UI/Inflight/Scanner/RecoverActiveProbes'), texturePath='res:/UI/Texture/Classes/ProbeScanner/16/recoverProbesIcon.png', func=self.RecoverActiveProbes, align=uiconst.TORIGHT, uniqueUiName=pConst.UNIQUE_NAME_RECOVER_PROBES)
    154         self.reconnectButton = ButtonIcon(hint=localization.GetByLabel('UI/Inflight/Scanner/ReconnectActiveProbes'), func=self.ReconnectToLostProbes, texturePath='res:/UI/Texture/Classes/ProbeScanner/16/reconnectProbesIcon.png', parent=self.probeStateCont, iconSize=16, width=16, align=uiconst.TORIGHT, padLeft=4)
    155         self.ConstructBonusIcons()
    156         if session.role & service.ROLE_QA:
    157             self.probeInfoContainer.GetMenu = self.QAGetMenu
    158 
    159     def OnSessionChanged(self, isRemote, session, change):
    160         self.LoadResultList()
    161 
    162     def QAGetMenu(self):
    163         return [('QA: Set Probe duration in seconds', self.QASetProbeDuration)]
    164 
    165     def QASetProbeDuration(self):
    166         qty = QtyPopup(7200, 30, 1)
    167         self.scanSvc.QAOverrideProbeExpiry(qty['qty'] * 1000)
    168 
    169     def LoadProbeIcon(self):
    170         typeID = self.scanSvc.GetActiveProbeTypeID()
    171         if not typeID:
    172             self.probeSprite.opacity = 0.3
    173             self.probeInfoContainer.tooltipPanelClassInfo = ScanProbeTooltip(typeID, self.GetProbeExpiryTimeLeft)
    174             typeID = probeLauncherTypeID
    175         else:
    176             self.probeSprite.opacity = 1.0
    177             self.probeInfoContainer.tooltipPanelClassInfo = ScanProbeTooltip(typeID, self.GetProbeExpiryTimeLeft)
    178         iconID = evetypes.GetIconID(typeID)
    179         texturePath = GetIconFile(iconID)
    180         self.probeSprite.texturePath = texturePath
    181 
    182     def ConstructBonusIcons(self):
    183         self.bonusesContainer = ContainerAutoSize(name='bonusesContainer', parent=self.probeStateCont, align=uiconst.TORIGHT, padRight=8)
    184         self.strengthBonusContainer = ContainerAutoSize(name='strengthBonusContainer', parent=self.bonusesContainer, align=uiconst.TOLEFT, state=uiconst.UI_NORMAL)
    185         self.strengthIcon = Sprite(name='strengthIcon', parent=Container(parent=self.strengthBonusContainer, align=uiconst.TOLEFT, width=16), align=uiconst.CENTER, texturePath='res:/UI/Texture/Classes/ProbeScanner/16/Strength.png', width=16, height=16, state=uiconst.UI_DISABLED, color=eveColor.LED_GREY)
    186         self.strengthLabel = Label(parent=ContainerAutoSize(parent=self.strengthBonusContainer, align=uiconst.TOLEFT), align=uiconst.CENTER, state=uiconst.UI_DISABLED, padLeft=3)
    187         self.deviationBonusContainer = ContainerAutoSize(name='deviationBonusContainer', parent=self.bonusesContainer, align=uiconst.TOLEFT, state=uiconst.UI_NORMAL, padLeft=6)
    188         self.deviationIcon = Sprite(name='deviationIcon', parent=Container(parent=self.deviationBonusContainer, align=uiconst.TOLEFT, width=16), align=uiconst.CENTER, texturePath='res:/UI/Texture/Classes/ProbeScanner/16/Deviation.png', width=16, height=16, state=uiconst.UI_DISABLED, color=eveColor.LED_GREY)
    189         self.deviationLabel = Label(parent=ContainerAutoSize(parent=self.deviationBonusContainer, align=uiconst.TOLEFT), align=uiconst.CENTER, state=uiconst.UI_DISABLED, padLeft=3)
    190         self.durationBonusContainer = ContainerAutoSize(name='durationContainer', parent=self.bonusesContainer, align=uiconst.TOLEFT, state=uiconst.UI_NORMAL, padLeft=6)
    191         self.durationIcon = Sprite(name='durationIcon', parent=Container(parent=self.durationBonusContainer, align=uiconst.TOLEFT, width=16), align=uiconst.CENTER, texturePath='res:/UI/Texture/Classes/ProbeScanner/16/Time.png', width=16, height=16, state=uiconst.UI_DISABLED, color=eveColor.LED_GREY)
    192         self.durationLabel = Label(parent=ContainerAutoSize(parent=self.durationBonusContainer, align=uiconst.TOLEFT), align=uiconst.CENTER, state=uiconst.UI_DISABLED, padLeft=3)
    193 
    194     def ActivateBonusTooltips(self):
    195         self.strengthBonusContainer.tooltipPanelClassInfo = ScanBonusTooltip(name='Strength', iconPath='res:/UI/Texture/Classes/ProbeScanner/16/Strength.png', totalValueFunc=self.scanBonusController.GetTotalScanStrength, baseValueFunc=self.scanBonusController.GetBaseScanStrength, skillBonusFunc=self.scanBonusController.GetScanStrengthBonusFromSkills, implantBonusFunc=self.scanBonusController.GetScanStrengthBonusFromImplants, shipBonusFunc=self.scanBonusController.GetScanStrengthBonusFromShip, moduleBonusFunc=self.scanBonusController.GetScanStrengthBonusFromModules, totalBonusFunc=self.scanBonusController.GetTotalScanStrengthBonus, boosterBonusFunc=self.scanBonusController.GetScanStrengthBonusFromBoosters)
    196         self.deviationBonusContainer.tooltipPanelClassInfo = ScanBonusTooltip(name='Deviation', iconPath='res:/UI/Texture/Classes/ProbeScanner/16/Deviation.png', totalValueFunc=self.scanBonusController.GetTotalScanDeviation, baseValueFunc=self.scanBonusController.GetBaseScanDeviation, skillBonusFunc=self.scanBonusController.GetScanDeviationBonusFromSkills, implantBonusFunc=self.scanBonusController.GetScanDeviationBonusFromImplants, shipBonusFunc=self.scanBonusController.GetScanDeviationBonusFromShip, moduleBonusFunc=self.scanBonusController.GetScanDeviationBonusFromModules, totalBonusFunc=self.scanBonusController.GetTotalScanDeviationBonus, boosterBonusFunc=self.scanBonusController.GetScanDeviationBonusFromBoosters)
    197         self.durationBonusContainer.tooltipPanelClassInfo = ScanBonusTooltip(name='Duration', iconPath='res:/UI/Texture/Classes/ProbeScanner/16/Time.png', totalValueFunc=self.scanBonusController.GetTotalScanDuration, baseValueFunc=self.scanBonusController.GetBaseScanDuration, skillBonusFunc=self.scanBonusController.GetScanDurationBonusFromSkills, implantBonusFunc=self.scanBonusController.GetScanDurationBonusFromImplants, shipBonusFunc=self.scanBonusController.GetScanDurationBonusFromShip, moduleBonusFunc=self.scanBonusController.GetScanDurationBonusFromModules, totalBonusFunc=self.scanBonusController.GetTotalScanDurationBonus, boosterBonusFunc=self.scanBonusController.GetScanDurationBonusFromBoosters)
    198 
    199     def DeactivateBonusTooltips(self):
    200         self.strengthBonusContainer.tooltipPanelClassInfo = None
    201         self.deviationBonusContainer.tooltipPanelClassInfo = None
    202         self.durationBonusContainer.tooltipPanelClassInfo = None
    203 
    204     def ConstructFilterCont(self):
    205         padding = (0, 4, 0, 0) if self._IsCompactHeaderWindow() else 0
    206         self.filterCont = Container(name='filterCont', parent=self.window.header.extra_content if self._IsCompactHeaderWindow() else self, align=uiconst.TOTOP, height=HEIGHT_COMPACT, padding=padding)
    207         if not self._IsCompactHeaderWindow():
    208             EveLabelMedium(name='ScanResultsLabel', parent=self.filterCont, text=GetByLabel('UI/Inflight/Scanner/ScanResults'), align=uiconst.CENTERLEFT, left=2)
    209         self.ignoredBox = IgnoredBox(name='IgnoredBox', parent=self.filterCont, text=GetByLabel('UI/Inflight/Scanner/Ignored', noIgnored=0), state=uiconst.UI_NORMAL, align=uiconst.TORIGHT, padLeft=4)
    210         self.ignoredBox.LoadTooltipPanel = self.LoadIgnoredTooltipPanel
    211         self.filteredBox = FilterBox(name='FilteredBox', parent=self.filterCont, text=GetByLabel('UI/Inflight/Scanner/Filtered', noFiltered=0), state=uiconst.UI_NORMAL, align=uiconst.TORIGHT, uniqueUiName=pConst.UNIQUE_NAME_FILTER_SCAN_RESULTS, padLeft=4)
    212         self.filteredBox.LoadTooltipPanel = self.LoadFilterTooltipPanel
    213         self.mapButton = ButtonIcon(name='solarSystemMapButton', parent=self.filterCont, align=uiconst.TOLEFT if self._IsCompactHeaderWindow() else uiconst.TORIGHT, width=24, iconSize=16, texturePath='res:/UI/Texture/Shared/Brackets/solarSystem.png', hint=GetByLabel('UI/Map/MapPallet/btnSolarsystemMap'), func=self.MapBtnClicked)
    214         self.mapButton.display = not IsProbeScanPanelEmbedded()
    215 
    216     def MapBtnClicked(self, *args):
    217         uicore.cmd.GetCommandAndExecute('CmdToggleSolarSystemMap')
    218 
    219     def ConstructFooter(self):
    220         self.formationButtonsContainer = ContainerAutoSize(name='FormationButtonsContainer', parent=self.bottomContainer, align=uiconst.TOLEFT, uniqueUiName=pConst.UNIQUE_NAME_PROBE_FORMATIONS)
    221         self.ConstructFormationButtons()
    222         buttonCont = ContainerAutoSize(name='AnalyzeButtonContainer', uniqueUiName=pConst.UNIQUE_NAME_PROBE_REFRESH, parent=self.bottomContainer, align=uiconst.TORIGHT, padLeft=8)
    223         self.primaryButtonController = AnalyzeButtonController(self.scanSvc)
    224         self.primaryButton = AnalyzeButton(name='PrimaryButton', parent=buttonCont, align=uiconst.CENTER, cmd=uicore.cmd.commandMap.GetCommandByName('CmdRefreshProbeScan'), fixedwidth=100, controller=self.primaryButtonController)
    225         sliderCont = Container(name='sliderCont', parent=Container(parent=self.bottomContainer, padLeft=8), align=uiconst.TORIGHT_PROP, width=1.0, maxWidth=120)
    226         self.sliderLabel = EveLabelMedium(name='sliderLabel', align=uiconst.TOTOP, parent=sliderCont)
    227         self.sizeSlider = Slider(name='SizeSlider', parent=sliderCont, align=uiconst.TOTOP, minValue=1, maxValue=8, on_dragging=self.UpdateProbeSizeFromSliderInput, callback=self.UpdateProbeSizeFromSliderInput, increments=[ i for i in range(1, 9) ], barHeight=10, uniqueUiName=pConst.UNIQUE_NAME_PROBE_SIZE_MODIFIER, hint=localization.GetByLabel('UI/Inflight/Scanner/ProbeSize'))
    228 
    229     def ConstructFormationButtons(self):
    230         self.formationButtonsByID = {}
    231         buttonSize = 32
    232         self.pinpointFormationButton = ButtonIcon(parent=self.formationButtonsContainer, fixedheight=buttonSize, iconSize=buttonSize, iconPadding=0, hint=GetByLabel('UI/Inflight/Scanner/LaunchPinpointFormation'), texturePath='res:/UI/Texture/classes/ProbeScanner/32/pinpointFormation.png', func=lambda *args: self.LaunchFormation(formations.PINPOINT_FORMATION), align=uiconst.TOLEFT, soundClick='msg_newscan_probe_formation_play')
    233         self.formationButtonsByID[formations.PINPOINT_FORMATION] = self.pinpointFormationButton
    234         self.spreadFormationButton = ButtonIcon(parent=self.formationButtonsContainer, iconSize=buttonSize, hint=GetByLabel('UI/Inflight/Scanner/LaunchSpreadFormation'), texturePath='res:/UI/Texture/classes/ProbeScanner/32/spreadFormation.png', func=lambda *args: self.LaunchFormation(formations.SPREAD_FORMATION), align=uiconst.TOLEFT, padLeft=2, soundClick='msg_newscan_probe_formation_play')
    235         self.formationButtonsByID[formations.SPREAD_FORMATION] = self.spreadFormationButton
    236         self.customFormationButton = FormationButton(name='CustomFormationButton', parent=self.formationButtonsContainer, width=buttonSize, iconSize=buttonSize, align=uiconst.TOLEFT, padLeft=2, launchFunc=self.LaunchFormation)
    237         self.formationButtonsByID[formations.CUSTOM_FORMATION] = self.customFormationButton
    238         self.centerOnSelfFormationButton = ButtonIcon(parent=self.formationButtonsContainer, iconSize=buttonSize, hint=GetByLabel('UI/Inflight/Scanner/CenterOnSelf'), texturePath='res:/UI/Texture/classes/ProbeScanner/32/centerProbes.png', func=lambda *args: self.LaunchFormation(formations.SELF_CENTER_FORMATION), align=uiconst.TOLEFT, padLeft=2, soundClick='msg_newscan_probe_formation_play')
    239         self.formationButtonsByID[formations.SELF_CENTER_FORMATION] = self.centerOnSelfFormationButton
    240 
    241     def OnProbeAdded(self, probe):
    242         self.UpdateLabels()
    243         self.UpdateSizeSlider()
    244         self.LoadProbeIcon()
    245 
    246     def OnProbeScannerUndocked(self):
    247         self.mapButton.Show()
    248 
    249     def OnProbeScannerDocked(self):
    250         self.mapButton.Hide()
    251 
    252     def UpdateSizeSlider(self):
    253         probeData = self.scanSvc.GetProbeData()
    254         if len(probeData) < 1:
    255             median = 0
    256         else:
    257             rangeSteps = [ data.rangeStep for probe, data in probeData.iteritems() ]
    258             median = self.GetMedian(rangeSteps)
    259         self.sizeSlider.SetValue(median)
    260 
    261     def GetMedian(self, list):
    262         if len(list) < 1:
    263             return None
    264         sortedList = sorted(list)
    265         listLength = len(list)
    266         index = (listLength - 1) // 2
    267         return sortedList[index]
    268 
    269     def OnProbeRemoved(self, probe):
    270         self.UpdateLabels()
    271         self.UpdateSizeSlider()
    272         self.LoadProbeIcon()
    273 
    274     def OnProbeRangeUpdated(self, probeID, scanRange):
    275         self.UpdateSizeSliderLabel()
    276         self.UpdateSizeSlider()
    277 
    278     def GetProbeScanRangeText(self, probeData):
    279         probeScanRangeText = self.GetAverageSizeInAU(probeData)
    280         probeScanRangeText = '' if probeScanRangeText == 0 else probeScanRangeText
    281         return probeScanRangeText
    282 
    283     def GetAverageSizeInAU(self, probeData):
    284         if len(probeData) <= 0:
    285             return 0
    286         sizes = []
    287         for probeID, data in probeData.iteritems():
    288             sizes.append(data.scanRange)
    289 
    290         medianSize = self.GetMedian(sizes)
    291         if medianSize < appConst.AU:
    292             probeScanRangeText = FmtDist(medianSize, maxdemicals=2)
    293         else:
    294             probeScanRangeText = FmtDist(medianSize, maxdemicals=0)
    295         return probeScanRangeText
    296 
    297     def UpdateProbeSizeFromSliderInput(self, slider):
    298         probeData = self.scanSvc.GetProbeData()
    299         if not probeData:
    300             return
    301         newRange = int(slider.GetValue())
    302         if len(probeData) <= 0:
    303             medianRange = 0
    304         else:
    305             rangeSteps = [ data.rangeStep for probe, data in probeData.iteritems() ]
    306             medianRange = self.GetMedian(rangeSteps)
    307         if newRange != medianRange:
    308             scale = 1.0
    309             if newRange < medianRange:
    310                 scale = 0.5
    311             elif newRange > medianRange:
    312                 scale = 2.0
    313             for x in range(abs(medianRange - newRange)):
    314                 self.scanSvc.ScaleFormation(scale)
    315 
    316         self.UpdateSizeSliderLabel()
    317 
    318     def UpdateSizeSliderLabel(self, *args):
    319         self.sliderLabel.SetText(self.GetProbeScanRangeText(self.scanSvc.GetProbeData()))
    320 
    321     def ConstructScroll(self):
    322         self.scanResultsContainer = Container(name='ScanResultsContainer', parent=self, align=uiconst.TOALL, clipChildren=True, padTop=0 if self._IsCompactHeaderWindow() else 4)
    323         self.resultScroll = ScanResults(name='resultScroll', parent=self.scanResultsContainer, id='probescannerwindow_resultScrollList', palette=self)
    324 
    325     def Close(self, *args):
    326         sm.UnregisterNotify(self)
    327         super(ProbeScannerPalette, self).Close()
    328 
    329     def GetSolarSystemView(self):
    330         from eve.client.script.ui.shared.mapView.solarSystemViewPanel import SolarSystemViewPanel
    331         solarSystemView = SolarSystemViewPanel.GetIfOpen()
    332         if solarSystemView and not solarSystemView.destroyed:
    333             return solarSystemView
    334 
    335     def ToggleFilterShortcut(self, vkey):
    336         localShortCuts = (uiconst.VK_1,
    337          uiconst.VK_2,
    338          uiconst.VK_3,
    339          uiconst.VK_4,
    340          uiconst.VK_5,
    341          uiconst.VK_6)
    342         if vkey not in localShortCuts:
    343             return False
    344         filterIndex = localShortCuts.index(vkey)
    345         self.ToggleFilter(filterIndex)
    346         return True
    347 
    348     def _ToggleShowAnomalies(self):
    349         toggleState = not settings.user.ui.Get('scannerShowAnomalies', True)
    350         settings.user.ui.Set('scannerShowAnomalies', toggleState)
    351         if toggleState:
    352             self.scanSvc.ShowAnomalies()
    353         else:
    354             self.scanSvc.StopShowingAnomalies()
    355         uthread.new(self.ReloadFilteredBoxTooltip)
    356 
    357     def ToggleFilter(self, filterIndex):
    358         if filterIndex in self._filter_toggle_queue:
    359             self._filter_toggle_queue.remove(filterIndex)
    360         else:
    361             self._filter_toggle_queue.add(filterIndex)
    362         self._UpdateFiltersThrottled()
    363 
    364     def _ToggleFilter(self, filterIndex):
    365         filterOptions = self.scanSvc.GetFilterOptions()
    366         filterOptionIDs = [ filterID for filterName, filterID in filterOptions if filterID < 0 ]
    367         filterID = filterOptionIDs[filterIndex - 1]
    368         activeFilters = self.scanSvc.GetActiveFilterSet()
    369         if filterID in activeFilters:
    370             self.scanSvc.RemoveFromActiveFilterSet(filterID)
    371         else:
    372             self.scanSvc.AddToActiveFilterSet(filterID)
    373         uthread.new(self.ReloadFilteredBoxTooltip)
    374 
    375     @uthread2.debounce(wait=0.1, leading=True)
    376     def _UpdateFiltersThrottled(self):
    377         while self._filter_toggle_queue:
    378             filter_index = self._filter_toggle_queue.pop()
    379             if filter_index == 0:
    380                 self._ToggleShowAnomalies()
    381             else:
    382                 self._ToggleFilter(filter_index)
    383 
    384     def OnSystemScanFilterChanged(self, *args):
    385         self.LoadResultList()
    386 
    387     def OnSystemScanBegun(self):
    388         self.Refresh()
    389         self.resultScroll.on_system_scan_started()
    390 
    391     def OnSystemScanDone(self):
    392         self.Refresh()
    393         self.resultScroll.on_system_scan_ended()
    394 
    395     def GetProbesTooltipPointer(self):
    396         return uiconst.POINT_TOP_3
    397 
    398     def LoadHelpTooltip(self, tooltipPanel, *args):
    399         tooltipPanel.columns = 2
    400         tooltipPanel.margin = (12, 4, 4, 4)
    401         tooltipPanel.cellPadding = (1, 1, 1, 1)
    402         tooltipPanel.AddLabelMedium(text=GetByLabel('UI/Inflight/Scanner/HelpToModify'), wrapWidth=120)
    403         tooltipPanel.AddLabelMedium(text=GetByLabel('UI/Inflight/Scanner/HelpHold'), align=uiconst.CENTERRIGHT)
    404         tooltipPanel.AddLabelMedium(text=GetByLabel('UI/Inflight/Scanner/FormationProbeRange'), wrapWidth=120)
    405         tooltipPanel.AddCell(ShortcutHint(text=trinity.app.GetKeyNameText(uiconst.VK_MENU), align=uiconst.TOPRIGHT), cellPadding=(6, 1, 1, 1))
    406         tooltipPanel.AddLabelMedium(text=GetByLabel('UI/Inflight/Scanner/FormationSpread'), wrapWidth=120)
    407         tooltipPanel.AddCell(ShortcutHint(text=trinity.app.GetKeyNameText(uiconst.VK_CONTROL), align=uiconst.TOPRIGHT), cellPadding=(6, 1, 1, 1))
    408         tooltipPanel.AddLabelMedium(text=GetByLabel('UI/Inflight/Scanner/OneProbe'), wrapWidth=120)
    409         tooltipPanel.AddCell(ShortcutHint(text=trinity.app.GetKeyNameText(uiconst.VK_SHIFT), align=uiconst.TOPRIGHT), cellPadding=(6, 1, 1, 1))
    410 
    411     def LoadFilterTooltipPanel(self, tooltipPanel, *args):
    412         return self._LoadFilterTooltipPanel(tooltipPanel, *args)
    413 
    414     def _LoadFilterTooltipPanel(self, tooltipPanel, *args):
    415         tooltipPanel.Flush()
    416         tooltipPanel.columns = 4
    417         tooltipPanel.state = uiconst.UI_NORMAL
    418         tooltipPanel.cellPadding = (5, 2, 5, 2)
    419         tooltipPanel.margin = (0, 1, 0, 1)
    420         header = eveLabel.EveLabelLarge(text=GetByLabel('UI/Inflight/Scanner/ShowResultsFor'), align=uiconst.CENTERLEFT, color=TextColor.HIGHLIGHT, padding=(0, 2, 0, 2))
    421         tooltipPanel.AddCell(header, colSpan=tooltipPanel.columns, cellPadding=(7, 3, 5, 3))
    422         tooltipPanel.AddRow(rowClass=ProbeTooltipCheckboxRow, text=GetByLabel('UI/Inflight/Scanner/AnomalySiteFilterLabel'), checked=settings.user.ui.Get('scannerShowAnomalies', True), func=self.OnShowAnomaliesCheckBoxChange, filterIndex=1)
    423         filterOptions = self.scanSvc.GetFilterOptions()
    424         activeFilters = self.scanSvc.GetActiveFilterSet()
    425         standardFilters = [ (filterName, filterID) for filterName, filterID in filterOptions if filterID < 0 ]
    426         for i, (filterName, filterID) in enumerate(standardFilters):
    427             if filterID < 0:
    428                 tooltipPanel.AddRow(rowClass=ProbeTooltipCheckboxRow, text=filterName, checked=filterID in activeFilters, settingsKey=filterID, func=self.OnFilterCheckBoxChange, filterIndex=i + 2)
    429 
    430         customFilters = [ (filterName, filterID) for filterName, filterID in filterOptions if filterID > 0 ]
    431         if customFilters:
    432             for filterName, filterID in customFilters:
    433                 if filterID > 0:
    434                     tooltipPanel.AddRow(rowClass=ProbeTooltipCheckboxRow, text=filterName, checked=filterID in activeFilters, settingsKey=filterID, func=self.OnFilterCheckBoxChange, deleteFunc=(self.DeleteFilter, (filterID,)), editFunc=(self.EditFilter, (filterID,)))
    435 
    436         buttonRow = tooltipPanel.AddRow(rowClass=ProbeTooltipButtonRow, text=GetByLabel('UI/Inflight/Scanner/CreateNewFilter'), texturePath='res:/UI/Texture/Classes/ProbeScanner/saveformationProbesIcon.png', func=AddFilter)
    437         self.filteredBoxTooltip = weakref.ref(tooltipPanel)
    438 
    439     def ReloadFilteredBoxTooltip(self):
    440         if not self.filteredBoxTooltip or self.destroyed:
    441             return
    442         filteredBoxTooltip = self.filteredBoxTooltip()
    443         if filteredBoxTooltip is not None:
    444             self._LoadFilterTooltipPanel(filteredBoxTooltip)
    445 
    446     def LoadIgnoredTooltipPanel(self, tooltipPanel, *args):
    447         tooltipPanel.Flush()
    448         tooltipPanel.margin = 3
    449         resultsIgnored = self.scanSvc.GetIgnoredResultsDesc()
    450         if not resultsIgnored:
    451             return
    452         scroll = ScrollContainer(align=uiconst.TOPLEFT, parent=tooltipPanel)
    453         scroll.isTabStop = False
    454         subGrid = LayoutGrid(parent=scroll, align=uiconst.TOPLEFT, columns=4)
    455         rowOrder = []
    456         if len(resultsIgnored) > 1:
    457             row = subGrid.AddRow(rowClass=ProbeTooltipButtonRow, text=GetByLabel('UI/Inflight/Scanner/ClearAllIgnoredResults'), texturePath='res:/UI/Texture/Classes/ProbeScanner/clearIgnoredMenu.png', func=self.ClearIgnoredResults, width=200)
    458             rowOrder.append(row)
    459         ids = sorted(resultsIgnored)
    460         for id, desc in ids:
    461             if desc:
    462                 displayDesc = GetByLabel('UI/Inflight/Scanner/ResultIdAndDesc', id=id, desc=desc)
    463             else:
    464                 displayDesc = id
    465             row = subGrid.AddRow(rowClass=ProbeTooltipButtonRow, text=displayDesc, texturePath='res:/UI/Texture/Classes/ProbeScanner/clearIgnoredMenu.png', func=self.UnIgnoreResult, funcArgs=(id,), width=200)
    466             rowOrder.append(row)
    467 
    468         subGrid.RefreshGridLayout()
    469         scroll.width = subGrid.width + (5 if len(rowOrder) > 10 else 0)
    470         totalHeight = 0
    471         for row in rowOrder[:10]:
    472             totalHeight += row.height
    473 
    474         scroll.height = totalHeight
    475         tooltipPanel.state = uiconst.UI_NORMAL
    476         self.ignoredTooltip = weakref.ref(tooltipPanel)
    477 
    478     def ClearIgnoredResults(self, *args):
    479         self.scanSvc.ClearIgnoredResults()
    480         ignoredTooltip = self.ignoredTooltip()
    481         if ignoredTooltip is not None:
    482             self.LoadIgnoredTooltipPanel(ignoredTooltip)
    483 
    484     def UnIgnoreResult(self, resultID, *args):
    485         self.scanSvc.ShowIgnoredResult(resultID)
    486         ignoredTooltip = self.ignoredTooltip()
    487         if ignoredTooltip is not None:
    488             self.LoadIgnoredTooltipPanel(ignoredTooltip)
    489 
    490     def OnShowAnomaliesCheckBoxChange(self, settingsKey, settingState, *args):
    491         settings.user.ui.Set('scannerShowAnomalies', settingState)
    492         if settingState:
    493             self.scanSvc.ShowAnomalies()
    494         else:
    495             self.scanSvc.StopShowingAnomalies()
    496         self.LoadResultList()
    497 
    498     def OnClick(self, *args):
    499         uicore.registry.SetFocus(self.resultScroll)
    500 
    501     def DeleteFilter(self, settingsKey):
    502         response = prompt_player_fsd_dialog('DeleteFilter', {'filterName': self.scanSvc.resultFilter.GetFilterName(settingsKey)}, uiconst.YESNO, suppress=uiconst.ID_YES)
    503         if response != uiconst.ID_YES:
    504             return
    505         self.scanSvc.DeleteFilter(settingsKey)
    506         self.scanSvc.RemoveFromActiveFilterSet(settingsKey)
    507         uthread.new(self.ReloadFilteredBoxTooltip)
    508 
    509     def OnFilterCheckBoxChange(self, settingsKey, settingState, *args):
    510         if settingState:
    511             self.scanSvc.AddToActiveFilterSet(settingsKey)
    512         else:
    513             self.scanSvc.RemoveFromActiveFilterSet(settingsKey)
    514 
    515     def ValidateProbesState(self, probeIDs, isEntryButton = False):
    516         probeData = self.scanSvc.GetProbeData()
    517         for probeID in probeIDs:
    518             if probeID in probeData:
    519                 probe = probeData[probeID]
    520                 if isEntryButton:
    521                     if probe.state not in (probeStateIdle, probeStateInactive):
    522                         return False
    523                 elif probe.state != probeStateIdle:
    524                     return False
    525 
    526         return True
    527 
    528     def LoadCurrentSolarSystem(self):
    529         self.LoadResultList()
    530 
    531     def OnNewScannerFilterSet(self, *args):
    532         self.LoadResultList()
    533 
    534     def OnProbePositionsUpdated(self):
    535         self.CheckButtonStates()
    536 
    537     def OnScannerDisconnected(self):
    538         self.LoadResultList()
    539         self.CheckButtonStates()
    540         self.UpdateLabels()
    541 
    542     def LaunchFormation(self, formationID):
    543         if formationID == formations.SELF_CENTER_FORMATION:
    544             self.scanSvc.CenterProbesOnMe(formationID)
    545         else:
    546             self.scanSvc.MoveProbesToFormation(formationID)
    547         self.UpdateSizeSlider()
    548         self.UpdateLabels()
    549 
    550     def EditFilter(self, filterID, *args):
    551         editor = ScannerFilterEditor.Open()
    552         editor.LoadData(filterID)
    553 
    554     def LoadResultList(self):
    555         if self.destroyed:
    556             return
    557         self.resultScroll.load_results()
    558 
    559     def CheckButtonStates(self):
    560         if self.destroyed:
    561             return
    562         canClaim = self.scanSvc.CanClaimProbes()
    563         if canClaim:
    564             self.recoverButton.Enable()
    565         else:
    566             self.recoverButton.Disable()
    567         probes = self.scanSvc.GetActiveProbes()
    568         allIdle = self.ValidateProbesState(probes)
    569         if probes and allIdle:
    570             self.recoverButton.Enable()
    571             self.sizeSlider.Show()
    572         else:
    573             self.recoverButton.Disable()
    574             self.sizeSlider.Hide()
    575         for formationID, button in self.formationButtonsByID.iteritems():
    576             try:
    577                 canLaunch = self.scanSvc.CanLaunchFormation(formationID)
    578             except KeyError:
    579                 if allIdle:
    580                     button.Enable()
    581                 else:
    582                     button.Disable()
    583                 continue
    584 
    585             if canLaunch and allIdle:
    586                 button.Enable()
    587             else:
    588                 button.Disable()
    589 
    590         self.UpdateProbeInfo()
    591         self.buttonRefreshTimer = AutoTimer(interval=500, method=self.CheckButtonStates)
    592 
    593     def GetProbeHandler(self):
    594         solarSystemView = self.GetSolarSystemView()
    595         if solarSystemView and solarSystemView.mapView:
    596             solarSystemHandler = solarSystemView.mapView.currentSolarsystem
    597             if solarSystemHandler and solarSystemHandler.solarsystemID == session.solarsystemid2:
    598                 return solarSystemHandler.probeHandler
    599 
    600     def RefreshProbeResults(self):
    601         probeHandler = self.GetProbeHandler()
    602         if probeHandler:
    603             probeHandler.SetResultFilter([], update=True)
    604 
    605     @UserErrorIfScanning
    606     def ReconnectToLostProbes(self, *args):
    607         self.scanSvc.ReconnectToLostProbes()
    608 
    609     @UserErrorIfScanning
    610     def RecoverActiveProbes(self, *args):
    611         probes = self.scanSvc.GetActiveProbes()
    612         self.scanSvc.RecoverProbes(probes)
    613         self.StopAnimatingProbeIcon()
    614 
    615     @UserErrorIfScanning
    616     def Analyze(self, *args):
    617         if IsAbyssalSpaceSystem(session.solarsystemid2):
    618             key = 'ProbeScannerAbyssalSpaceWarning'
    619             response = prompt_player_fsd_dialog(key, buttons=uiconst.YESNO, suppress=uiconst.ID_YES)
    620             if response == uiconst.ID_NO:
    621                 self.CheckButtonStates()
    622                 return
    623         elif IsVoidSpaceSystem(session.solarsystemid2):
    624             raise UserError('ProbeScannerVoidSpaceHint')
    625         try:
    626             self.scanSvc.RequestScans()
    627         except UserError as e:
    628             self.CheckButtonStates()
    629             raise e
    630         finally:
    631             self.LoadResultList()
    632 
    633     def Confirm(self, *args):
    634         uthread.new(self.primaryButtonController.click)
    635 
    636     def Refresh(self):
    637         self.refreshTimer = AutoTimer(interval=200, method=self.DoRefresh)
    638 
    639     def DoRefresh(self):
    640         self.refreshTimer = None
    641         if self.destroyed:
    642             return
    643         self.CheckButtonStates()
    644         self.LoadResultList()
    645         self.UpdateLabels()
    646 
    647     def UpdateLabels(self):
    648         self.UpdateSizeSliderLabel()
    649         self.UpdateProbeInfo()
    650 
    651     def UpdateProbeInfoText(self):
    652         probeData = self.scanSvc.GetProbeData()
    653         numProbes = len(probeData)
    654         if numProbes:
    655             text = 'X %s' % numProbes
    656         elif not self.scanSvc.HasOnlineProbeLauncher():
    657             text = GetByLabel('UI/Inflight/Scanner/NoLauncherFitted')
    658         elif self.scanSvc.GetChargesInProbeLauncher():
    659             text = GetByLabel('UI/Inflight/Scanner/NoProbesLaunched')
    660         else:
    661             text = GetByLabel('UI/Inflight/Scanner/NoProbesInLauncher')
    662         self.probesLaunchedLabel.SetText(text)
    663         color = Label.default_color if numProbes else eveColor.WARNING_ORANGE
    664         self.probesLaunchedLabel.SetRGBA(*color)
    665 
    666     def UpdateBonusLabelsText(self):
    667         if self.scanSvc.GetProbeData():
    668             self.strengthLabel.SetText(self.FormatBonusAmount(self.scanBonusController.GetTotalScanStrength(), fractions=1))
    669             self.deviationLabel.SetText(self.FormatBonusAmount(self.scanBonusController.GetTotalScanDeviation(), fractions=3, suffix=' AU'))
    670             self.durationLabel.SetText(self.FormatBonusAmount(self.scanBonusController.GetTotalScanDuration(), fractions=0, suffix='s'))
    671 
    672     def UpdateBonusLabelVisibility(self):
    673         if self.scanSvc.GetProbeData():
    674             self.bonusesContainer.Show()
    675             self.strengthLabel.display = self.deviationLabel.display = self.durationLabel.display = False
    676         else:
    677             self.bonusesContainer.Hide()
    678 
    679     def UpdateReconnectButtonVisibility(self):
    680         if self.scanSvc.GetProbeData():
    681             self.reconnectButton.Hide()
    682         elif self.scanSvc.HasOnlineProbeLauncher():
    683             self.reconnectButton.Show()
    684         else:
    685             self.reconnectButton.Hide()
    686 
    687     def FormatBonusAmount(self, amount, fractions, suffix = ''):
    688         if amount == 0:
    689             return '-'
    690         else:
    691             return FmtAmt(amount, showFraction=fractions) + suffix
    692 
    693     def GetProbeExpiryTimeLeft(self):
    694         probeData = self.scanSvc.GetProbeData()
    695         if len(probeData) <= 0:
    696             return None
    697         else:
    698             timeLeft = 0
    699             for probeID, data in probeData.iteritems():
    700                 timeLeft = long(gametime.GetSecondsUntilSimTime(data.expiry)) * gametime.SEC
    701                 break
    702 
    703             if timeLeft <= 0:
    704                 self.StopAnimatingProbeIcon()
    705                 return timeLeft
    706             if timeLeft >= gametime.HOUR:
    707                 self.StopAnimatingProbeIcon()
    708                 return localization.formatters.FormatTimeIntervalShortWritten(timeLeft, showFrom='day', showTo='minute')
    709             if timeLeft <= gametime.MIN * 5:
    710                 self.StartBlinkingProbeIcon()
    711             return localization.formatters.FormatTimeIntervalShortWritten(timeLeft, showFrom='day', showTo='second')
    712 
    713     def StartBlinkingProbeIcon(self):
    714         if not self.isAnimatingProbeIcon:
    715             PlaySound('msg_newscan_probe_expire_play')
    716             animations.BlinkIn(self.probeSprite, duration=1, loops=uiconst.ANIM_REPEAT, startVal=0.1, curveType=uiconst.ANIM_BOUNCE)
    717             self.isAnimatingProbeIcon = True
    718 
    719     def StopAnimatingProbeIcon(self):
    720         if self.isAnimatingProbeIcon:
    721             animations.StopAllAnimations(self.probeSprite)
    722             self.isAnimatingProbeIcon = False
    723 
    724     def OnRefreshScanResults(self):
    725         self.Refresh()
    726 
    727     def OnBallparkSetState(self):
    728         self.Refresh()
    729 
    730     def ShowFilteredAndIgnored(self, filtered, ignored, filteredAnomalies):
    731         self.filteredBox.SetText(GetByLabel('UI/Inflight/Scanner/Filtered', noFiltered=filtered + filteredAnomalies))
    732         self.ignoredBox.UpdateIgnoredAmount(ignored)
    733 
    734     def OnReconnectToProbesAvailable(self):
    735         self.CheckButtonStates()
    736         self.UpdateProbeInfo()
    737 
    738     def OnModuleFitted(self, charId, flag, typeID, groupID):
    739         self.UpdateProbeInfo()
    740 
    741     def OnModuleOnlineChange(self, item, oldValue, newValue):
    742         self.UpdateProbeInfo()
    743 
    744     def UpdateProbeInfo(self):
    745         if not self.destroyed:
    746             self.UpdateBonusLabelVisibility()
    747             self.UpdateBonusLabelsText()
    748             self.UpdateReconnectButtonVisibility()
    749             self.UpdateProbeInfoText()
    750             self.GetProbeExpiryTimeLeft()
    751 
    752     def OnChargeLoadedToModule(self):
    753         blue.synchro.Sleep(1000)
    754         self.UpdateProbeInfo()
    755         self.LoadProbeIcon()