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

directionalScannerPalette.py (28934B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\inflight\scannerFiles\directionalScannerPalette.py
      2 import math
      3 import weakref
      4 import blue
      5 import evetypes
      6 import trinity
      7 import uthread
      8 from carbon.client.script.environment.AudioUtil import PlaySound
      9 from carbon.common.script.sys.serviceConst import ROLE_GML, ROLE_WORLDMOD
     10 from carbon.common.script.util.format import FmtDist
     11 from carbonui import ButtonVariant, Density, TextColor, uiconst
     12 from carbonui.button import styling
     13 from carbonui.control.button import Button
     14 from carbonui.control.buttonIcon import ButtonIcon
     15 from carbonui.control.scrollentries import ScrollEntryNode
     16 from carbonui.control.singlelineedits.singleLineEditFloat import SingleLineEditFloat
     17 from carbonui.control.singlelineedits.singleLineEditInteger import SingleLineEditInteger
     18 from carbonui.control.slider import Slider
     19 from carbonui.window.segment.underlay import WindowSegmentUnderlay
     20 from carbonui.primitives.container import Container
     21 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     22 from carbonui.primitives.flowcontainer import FlowContainer
     23 from carbonui.primitives.gradientSprite import GradientConst, GradientSprite
     24 from carbonui.primitives.layoutGrid import LayoutGrid
     25 from clientsettings.setting import UserSettingEnum
     26 from carbonui.uianimations import animations
     27 from carbonui.uicore import uicore
     28 from carbonui.util.bunch import Bunch
     29 from eve.client.script.ui.control import eveLabel
     30 from eve.client.script.ui.control.eveLabel import EveLabelSmall, EveLabelMedium
     31 from eve.client.script.ui.control.eveScroll import Scroll
     32 from eve.client.script.ui.control.tooltips import ShortcutHint
     33 from eve.client.script.ui.inflight.overview import overviewUtil
     34 from eve.client.script.ui.inflight.scannerFiles import scanButton
     35 from eve.client.script.ui.inflight.scannerFiles.directionalScanResultEntry import DirectionalScanResultEntry
     36 from eve.client.script.ui.inflight.scannerFiles.directionalScanUtil import ConvertAuToKm, ConvertKmToAu, GetActiveScanMode, GetScanAngle, GetScanRange, IsDscanConeShown, MIN_RANGE_AU, RANGEMODE_AU, RANGEMODE_KM, SCANMODE_CAMERA, SetScanAngle, SetScanConeDisplayState, SetScanRange, ToggleScanMode, GetMaxRangeAU, GetMaxRangeKM
     37 from eve.client.script.ui.inflight.scannerFiles.scannerToolsUIComponents import FilterBox
     38 from eve.client.script.ui.inflight.scannerFiles.scannerUtil import COLOR_DSCAN, IsDirectionalScanPanelEmbedded
     39 from eve.client.script.ui.shared.mapView.controls.mapViewCheckbox import MapViewCheckbox
     40 from eve.client.script.ui.shared.maps.browserwindow import MapBrowserWnd
     41 from eve.common.lib import appConst
     42 from localization import GetByLabel
     43 from qtyTooltip.qtyConst import EDIT_INPUT_TYPE_NO_NUMBERHINT
     44 from signals import Signal
     45 ANGLE_INCREMENTS = [5,
     46  15,
     47  30,
     48  60,
     49  90,
     50  180,
     51  360]
     52 MIN_WINDOW_WIDTH = 320
     53 MIN_WINDOW_HEIGHT = 200
     54 TOP_CONT_HEIGHT = 18
     55 RANGE_EDIT_MODE_SETTING = UserSettingEnum('scanner_rangeEditMode', RANGEMODE_AU, options=[RANGEMODE_KM, RANGEMODE_AU])
     56 
     57 def ToggleRangeEditModeSetting(*args):
     58     if RANGE_EDIT_MODE_SETTING.is_equal(RANGEMODE_AU):
     59         RANGE_EDIT_MODE_SETTING.set(RANGEMODE_KM)
     60     else:
     61         RANGE_EDIT_MODE_SETTING.set(RANGEMODE_AU)
     62 
     63 
     64 class DistanceEditCont(Container):
     65 
     66     def ApplyAttributes(self, attributes):
     67         super(DistanceEditCont, self).ApplyAttributes(attributes)
     68         RANGE_EDIT_MODE_SETTING.on_change.connect(self.OnRangeEditModeSettingChanged)
     69         self.on_changing = Signal('on_changing')
     70         self.on_changed = Signal('on_changed')
     71         self.ConstructLayout()
     72         self.UpdateInputVisibility()
     73 
     74     def ConstructLayout(self):
     75         self.rangeLabel = EveLabelMedium(text=GetByLabel('UI/Inflight/Scanner/Range'), parent=ContainerAutoSize(parent=self, align=uiconst.TOLEFT), align=uiconst.CENTERLEFT, state=uiconst.UI_DISABLED, padRight=4)
     76         self.unitToggleButton = Button(parent=self, align=uiconst.TORIGHT, func=ToggleRangeEditModeSetting, density=Density.COMPACT, padLeft=4, variant=ButtonVariant.GHOST)
     77         self.UpdateUnitToggleButtonLabel()
     78         self.auInput = SingleLineEditFloat(name='auInput', parent=self, align=uiconst.TOALL, OnReturn=self.OnEditChanged, OnFocusLost=self.OnEditChanging, OnChange=self.OnEditChanging, inputType=EDIT_INPUT_TYPE_NO_NUMBERHINT, state=uiconst.UI_HIDDEN, minValue=MIN_RANGE_AU, maxValue=GetMaxRangeAU(), decimalPlaces=True)
     79         self.auInput.SetHistoryVisibility(False)
     80         self.kmInput = SingleLineEditInteger(name='kmInput', parent=self, align=uiconst.TOALL, OnReturn=self.OnEditChanged, OnFocusLost=self.OnEditChanging, OnChange=self.OnEditChanging, inputType=EDIT_INPUT_TYPE_NO_NUMBERHINT, state=uiconst.UI_HIDDEN, minValue=ConvertAuToKm(MIN_RANGE_AU), maxValue=GetMaxRangeKM())
     81 
     82     def UpdateMaxValue(self):
     83         self.auInput.SetMaxValue(GetMaxRangeAU())
     84         self.auInput.ClampMinMaxValue()
     85         self.kmInput.SetMaxValue(GetMaxRangeKM())
     86         self.kmInput.ClampMinMaxValue()
     87 
     88     def GetScanRangeAU(self):
     89         if RANGE_EDIT_MODE_SETTING.is_equal(RANGEMODE_KM):
     90             scanRange = self.kmInput.GetValue()
     91             scanRangeAU = ConvertKmToAu(scanRange)
     92             SetScanRange(scanRange)
     93         else:
     94             scanRangeAU = self.auInput.GetValue()
     95             SetScanRange(ConvertAuToKm(scanRangeAU))
     96         return scanRangeAU
     97 
     98     def SetScanRangeAU(self, scanRangeAU):
     99         if RANGE_EDIT_MODE_SETTING.is_equal(RANGEMODE_KM):
    100             kmValue = ConvertAuToKm(scanRangeAU)
    101             self.kmInput.SetValue(kmValue, docallback=False)
    102         else:
    103             self.auInput.SetValue(scanRangeAU, docallback=False)
    104 
    105     def IsRangeEditInFocus(self):
    106         return uicore.registry.GetFocus() in (self.kmInput, self.auInput)
    107 
    108     def OnEditChanged(self, *args):
    109         self.on_changed()
    110 
    111     def OnEditChanging(self, *args):
    112         self.on_changing()
    113 
    114     def ShowKMInput(self):
    115         self.kmInput.Show()
    116         self.auInput.Hide()
    117 
    118     def ShowAUInput(self):
    119         self.auInput.Show()
    120         self.kmInput.Hide()
    121 
    122     def UpdateUnitToggleButtonLabel(self):
    123         if RANGE_EDIT_MODE_SETTING.is_equal(RANGEMODE_AU):
    124             self.unitToggleButton.SetLabel(GetByLabel('UI/Inflight/Scanner/UnitAU'))
    125         else:
    126             self.unitToggleButton.SetLabel(GetByLabel('UI/Inflight/Scanner/UnitKm'))
    127 
    128     def OnRangeEditModeSettingChanged(self, *args):
    129         self.UpdateInputVisibility()
    130 
    131     def UpdateInputVisibility(self):
    132         if RANGE_EDIT_MODE_SETTING.is_equal(RANGEMODE_AU):
    133             scanRangeAU = ConvertKmToAu(GetScanRange())
    134             self.ShowAUInput()
    135             self.auInput.SetValue(scanRangeAU)
    136             self.unitToggleButton.SetLabel(GetByLabel('UI/Inflight/Scanner/UnitAU'))
    137         else:
    138             self.ShowKMInput()
    139             self.kmInput.SetValue(GetScanRange())
    140             self.unitToggleButton.SetLabel(GetByLabel('UI/Inflight/Scanner/UnitKm'))
    141 
    142     def _OnSizeChange_NoBlock(self, width, height):
    143         self.rangeLabel.display = width > 150
    144 
    145 
    146 class DirectionalScannerPalette(Container):
    147     __notifyevents__ = ['OnOverviewPresetSaved',
    148      'OnBallparkSetState',
    149      'OnDirectionalScanComplete',
    150      'OnDirectionalScanStarted',
    151      'OnDirectionalScannerScanModeChanged',
    152      'OnDirectionalScannerRangeChanged',
    153      'OnDirectionalScannerUndocked',
    154      'OnDirectionalScannerDocked',
    155      'OnAttributes']
    156     performAnotherScan = False
    157     filteredBoxTooltip = None
    158 
    159     def ApplyAttributes(self, attributes):
    160         super(DirectionalScannerPalette, self).ApplyAttributes(attributes)
    161         scanOnOpen = attributes.Get('scanOnOpen', True)
    162         self.window = attributes.Get('window', None)
    163         self.scanSvc = sm.GetService('directionalScanSvc')
    164         self.scanresult = []
    165         sm.RegisterNotify(self)
    166         self.ConstructLayout()
    167         if scanOnOpen and not self.scanSvc.IsScanning():
    168             self.DirectionalScan()
    169         self.UpdateScroll()
    170 
    171     def Reconstruct(self):
    172         self.Flush()
    173         self.headerCont.Flush()
    174         self.ConstructLayout()
    175         self.UpdateScroll()
    176 
    177     def Close(self, *args, **kwds):
    178         Container.Close(self, *args, **kwds)
    179 
    180     def Confirm(self, *args):
    181         self.scanButtonController.click()
    182 
    183     def ToggleFitlerShortcut(self, vkey):
    184         localShortCuts = (uiconst.VK_1,
    185          uiconst.VK_2,
    186          uiconst.VK_3,
    187          uiconst.VK_4,
    188          uiconst.VK_5,
    189          uiconst.VK_6,
    190          uiconst.VK_7,
    191          uiconst.VK_8)
    192         if vkey not in localShortCuts:
    193             return False
    194         shortCutIndex = localShortCuts.index(vkey)
    195         presetOptions = self.GetPresetOptions()
    196         filterName, filterID = presetOptions[shortCutIndex]
    197         try:
    198             uthread.new(self.OnFilterChange, filterID, True)
    199         except IndexError:
    200             pass
    201 
    202         return True
    203 
    204     def ConstructLayout(self):
    205         padTop = self.window.content_padding[0] if self.window else 8
    206         self.bottomCont = Container(name='bottomCont', parent=self, align=uiconst.TOBOTTOM, padTop=padTop, height=styling.get_height(Density.NORMAL))
    207         if self.window:
    208             pad_left, _, pad_right, pad_bottom = self.window.content_padding
    209             WindowSegmentUnderlay(bgParent=self.bottomCont, padding=(-pad_left,
    210              -pad_bottom,
    211              -pad_right,
    212              -pad_bottom))
    213         self.ConstructScanButton()
    214         self.sliderCont = Container(name='sliderCont', parent=self.bottomCont)
    215         self.ConstructDistanceCont()
    216         self.ConstructAngleCont()
    217         self.AdjustBottomContHeight()
    218         if self._IsCompactHeaderWindow():
    219             self.headerCont = self.window.header.extra_content
    220         else:
    221             self.headerCont = Container(parent=self, name='headerCont', align=uiconst.TOTOP, state=uiconst.UI_PICKCHILDREN, padBottom=2, height=styling.get_height(Density.NORMAL))
    222         self.ConstructScroll()
    223         self.ReconstructHeader()
    224 
    225     def ConstructScanButton(self):
    226         self.scanButtonController = scanButton.ScanButtonController(directional_scan_service=self.scanSvc, service_manager=sm)
    227         scanButtonCont = ContainerAutoSize(name='scanButtonCont', align=uiconst.TORIGHT, parent=self.bottomCont, padLeft=8)
    228         self.scanButton = scanButton.ScanButton(parent=scanButtonCont, align=uiconst.CENTERRIGHT, cmd=uicore.cmd.commandMap.GetCommandByName('CmdRefreshDirectionalScan'), controller=self.scanButtonController)
    229 
    230     def ConstructDistanceCont(self):
    231         distanceCont = Container(name='distanceCont', parent=self.sliderCont, align=uiconst.TOLEFT_PROP, width=0.5, padRight=4)
    232         self.distanceEditCont = DistanceEditCont(parent=distanceCont, align=uiconst.TOTOP, height=TOP_CONT_HEIGHT)
    233         self.distanceEditCont.on_changing.connect(self.OnScanRangeEditChange)
    234         self.distanceEditCont.on_changed.connect(self.OnScanRangeEditReturn)
    235         self.ConstructDistanceSlider(distanceCont)
    236 
    237     def UpdateMaxValue(self):
    238         self.distanceEditCont.UpdateMaxValue()
    239         maxRangeAu = GetMaxRangeAU()
    240         incrementValues = self._GetDistanceIncrements(maxRangeAu)
    241         self.distanceSlider.maxValue = maxRangeAu
    242         self.distanceSlider.SetIncrements(incrementValues)
    243 
    244     def UpdateUnitToggleButtonLabel(self):
    245         if RANGE_EDIT_MODE_SETTING.is_equal(RANGEMODE_AU):
    246             self.unitToggleButton.SetLabel(GetByLabel('UI/Inflight/Scanner/UnitAU'))
    247         else:
    248             self.unitToggleButton.SetLabel(GetByLabel('UI/Inflight/Scanner/UnitKm'))
    249 
    250     def ConstructDistanceSlider(self, distanceCont):
    251         startingKmValue = GetScanRange()
    252         startingAuValue = ConvertKmToAu(startingKmValue)
    253         maxRangeAu = GetMaxRangeAU()
    254         increments = self._GetDistanceIncrements(maxRangeAu)
    255         self.distanceSlider = Slider(name='distanceSlider', parent=distanceCont, minValue=0, maxValue=maxRangeAu, callback=self.EndSetDistanceSliderValue, on_dragging=self.OnSetDistanceSliderValue, increments=increments, align=uiconst.TOTOP, barHeight=10, top=3, height=16)
    256         self.distanceSlider.SetValue(startingAuValue)
    257         self.distanceSlider.barCont.LoadTooltipPanel = self.LoadDistanceSliderTooltipPanel
    258 
    259     def _GetDistanceIncrements(self, maxRangeAu):
    260         minIncrement = max(MIN_RANGE_AU, 0.1)
    261         increments = [minIncrement, 1] + [ x for x in range(5, int(maxRangeAu) + 1, 5) ] + [maxRangeAu]
    262         return increments
    263 
    264     def ConstructAngleCont(self):
    265         angleCont = Container(name='angleCont', parent=self.sliderCont, align=uiconst.TOLEFT_PROP, width=0.5, padLeft=4)
    266         self.angleTopCont = Container(name='topCont', parent=angleCont, align=uiconst.TOTOP, height=TOP_CONT_HEIGHT)
    267         self.angleLabel = EveLabelMedium(parent=ContainerAutoSize(parent=self.angleTopCont, align=uiconst.TOLEFT), align=uiconst.CENTERLEFT, state=uiconst.UI_DISABLED)
    268         self.UpdateAngleSliderLabel()
    269         startingAngle = int(round(math.degrees(GetScanAngle())))
    270         if startingAngle not in ANGLE_INCREMENTS:
    271             startingAngle = ANGLE_INCREMENTS[-1]
    272         self.angleSlider = Slider(name='angleSlider', parent=angleCont, align=uiconst.TOTOP, value=startingAngle, minValue=5, maxValue=360, increments=ANGLE_INCREMENTS, isEvenIncrementsSlider=True, callback=self.EndSetAngleSliderValue, on_dragging=self.UpdateAngleSliderLabel, height=16, barHeight=10, top=3)
    273 
    274     def AdjustBottomContHeight(self):
    275         distanceContent = self.distanceEditCont.height + self.distanceSlider.top + self.distanceSlider.height
    276         angleContentHeight = self.angleTopCont.height + self.angleSlider.top + self.angleSlider.height
    277         self.bottomCont.height = max(self.bottomCont.height, distanceContent, angleContentHeight)
    278 
    279     def ConstructScroll(self):
    280         self.scroll = Scroll(name='dirscroll', parent=self)
    281         self.scroll.sr.fixedColumns = DirectionalScanResultEntry.GetFixedColumns()
    282         self.scroll.sr.defaultColumnWidth = DirectionalScanResultEntry.GetColumnsDefaultSize()
    283         self.scroll.sr.id = 'scanner_dirscroll'
    284         self.scroll.OnChar = None
    285         self.animBGCont = Container(parent=self.scroll)
    286         self.animBG = GradientSprite(parent=self.animBGCont, align=uiconst.TORIGHT_PROP, width=1.0, colorType=uiconst.COLORTYPE_FLASH, blendMode=trinity.TR2_SBM_ADD, rotation=0.0, color=COLOR_DSCAN, rgbData=[(0, (1, 1, 1))], alphaData=[(0, 0),
    287          (0.95, 0.3),
    288          (0.99, 0.5),
    289          (1, 1)], alphaInterp=GradientConst.INTERP_LINEAR, colorInterp=GradientConst.INTERP_LINEAR, opacity=0)
    290 
    291     def ReconstructHeader(self):
    292         self.headerCont.Flush()
    293         if not self._IsCompactHeaderWindow():
    294             EveLabelMedium(text=GetByLabel('UI/Inflight/Scanner/ScanResults'), parent=self.headerCont, state=uiconst.UI_DISABLED, align=uiconst.CENTERLEFT, left=2)
    295         self.filteredBox = FilterBox(parent=self.headerCont, text='-', state=uiconst.UI_NORMAL, align=uiconst.CENTERRIGHT if self._IsCompactHeaderWindow() else uiconst.TORIGHT, padLeft=4, density=Density.COMPACT, maxWidth=120)
    296         self.filteredBox.LoadTooltipPanel = self.LoadFilterTooltipPanel
    297         buttonCont = ContainerAutoSize(name='buttonCont', align=uiconst.TOLEFT if self._IsCompactHeaderWindow() else uiconst.TORIGHT, parent=self.headerCont)
    298         self.alignWithCameraBtn = ButtonIcon(name='alignWithCameraBtn', parent=buttonCont, align=uiconst.TOLEFT, width=16, iconSize=16, texturePath='res:/UI/Texture/classes/MapView/alignwithCamera.png', func=self.OnAlignWithCameraBtn, hint=GetByLabel('UI/Inflight/Scanner/AlignWithCamera'))
    299         self.UpdateAlignWithCameraBtn()
    300         self.showConeBtn = ButtonIcon(name='showConeBtn', parent=buttonCont, align=uiconst.TOLEFT, padLeft=4, width=16, iconSize=16, texturePath='res:/UI/Texture/classes/MapView/dScanIcon.png', func=self.OnShowConeBtn, hint=GetByLabel('UI/Inflight/Scanner/ShowScanCone'))
    301         self.UpdateShowConeButton()
    302         self.mapButton = ButtonIcon(name='solarSystemMapButton', parent=buttonCont, align=uiconst.TOLEFT, iconSize=16, width=16, padLeft=8, texturePath='res:/UI/Texture/Shared/Brackets/solarSystem.png', hint=GetByLabel('UI/Map/MapPallet/btnSolarsystemMap'), func=self.MapBtnClicked)
    303         self.mapButton.display = not IsDirectionalScanPanelEmbedded()
    304 
    305     def _IsCompactHeaderWindow(self):
    306         return self.window and self.window.compact and not self.window.stacked and not self.window.collapsed
    307 
    308     def MapBtnClicked(self, *args):
    309         uicore.cmd.GetCommandAndExecute('CmdToggleSolarSystemMap')
    310 
    311     def LoadDistanceSliderTooltipPanel(self, tooltipPanel, *args):
    312         if IsDirectionalScanPanelEmbedded():
    313             tooltipPanel.LoadGeneric2ColumnTemplate()
    314             shortcutTxt = self.scanButton.cmd.GetShortcutAsString()
    315             tooltipPanel.AddLabelShortcut(GetByLabel('UI/Inflight/Scanner/AdjustRange'), GetByLabel('UI/Inflight/Scanner/AdjustRangeShortcut', shortcut=shortcutTxt))
    316 
    317     def UpdateAlignWithCameraBtn(self):
    318         if GetActiveScanMode() == SCANMODE_CAMERA:
    319             self.alignWithCameraBtn.SetSelected()
    320         else:
    321             self.alignWithCameraBtn.SetDeselected()
    322 
    323     def OnAlignWithCameraBtn(self):
    324         ToggleScanMode()
    325         self.UpdateAlignWithCameraBtn()
    326 
    327     def OnClick(self, *args):
    328         uicore.registry.SetFocus(self.scroll)
    329 
    330     def UpdateShowConeButton(self):
    331         if IsDscanConeShown():
    332             self.showConeBtn.SetSelected()
    333         else:
    334             self.showConeBtn.SetDeselected()
    335 
    336     def OnShowConeBtn(self):
    337         SetScanConeDisplayState(not IsDscanConeShown())
    338         self.UpdateShowConeButton()
    339 
    340     def LoadFilterTooltipPanel(self, tooltipPanel, *args):
    341         tooltipPanel.Flush()
    342         tooltipPanel.columns = 1
    343         tooltipPanel.cellPadding = 2
    344         tooltipPanel.state = uiconst.UI_NORMAL
    345         header = eveLabel.EveLabelLarge(text=GetByLabel('UI/Inflight/Scanner/ShowResultsFor'), align=uiconst.CENTERLEFT, color=TextColor.HIGHLIGHT, padding=(0, 2, 0, 2))
    346         tooltipPanel.AddCell(header, colSpan=tooltipPanel.columns, cellPadding=(7, 3, 5, 3))
    347         tooltipPanel.scroll = Scroll(parent=tooltipPanel, align=uiconst.TOPLEFT, width=220, height=200)
    348         tooltipPanel.scroll.OnUpdatePosition = self.OnScrollPositionChanged
    349         self.filteredBoxTooltip = weakref.ref(tooltipPanel)
    350         self.LoadFilters()
    351 
    352     def LoadFilters(self):
    353         filteredBoxTooltip = self.filteredBoxTooltip()
    354         if not filteredBoxTooltip:
    355             return
    356         scrollPosition = settings.char.ui.Get('directionalScanFilterPos', 0.0)
    357         presetSelected = settings.user.ui.Get('scanner_presetInUse', None)
    358         presetOptions = self.GetPresetOptions()
    359         scrollEntries = []
    360         for i, (filterName, filterID) in enumerate(presetOptions):
    361             if i < 10:
    362                 filterIndex = (i + 1) % 10
    363             else:
    364                 filterIndex = None
    365             scrollNode = ScrollEntryNode(label=filterName, checked=filterID == presetSelected, cfgname=filterID, OnChange=self.OnFilterCheckBoxChange, entryWidth=210, decoClass=FilterOptionEntry, filterIndex=filterIndex, group='directionalScannerFilterGroup')
    366             scrollEntries.append(scrollNode)
    367 
    368         filteredBoxTooltip.scroll.Load(contentList=scrollEntries, scrollTo=scrollPosition)
    369         filteredBoxTooltip.scroll.height = min(200, filteredBoxTooltip.scroll.GetContentHeight() + 2)
    370 
    371     def OnScrollPositionChanged(self, *args, **kwargs):
    372         filteredBoxTooltip = self.filteredBoxTooltip()
    373         if filteredBoxTooltip:
    374             settings.char.ui.Set('directionalScanFilterPos', filteredBoxTooltip.scroll.GetScrollProportion())
    375 
    376     def OnFilterCheckBoxChange(self, checkbox, *args):
    377         settingKey = checkbox.GetSettingsKey()
    378         self.OnFilterChange(settingKey, True)
    379 
    380     def OnFilterChange(self, settingKey, settingState, *args):
    381         settings.user.ui.Set('scanner_presetInUse', settingKey)
    382         if self.scanresult:
    383             uthread.new(self.UpdateScroll)
    384         else:
    385             self.DirectionalScan()
    386         self.ReloadFilteredBoxTooltip()
    387 
    388     def ReloadFilteredBoxTooltip(self):
    389         if not self.filteredBoxTooltip or self.destroyed:
    390             return
    391         filteredBoxTooltip = self.filteredBoxTooltip()
    392         if filteredBoxTooltip is not None:
    393             self.LoadFilters()
    394 
    395     def UpdateRangeInput(self, scanRangeKM):
    396         if RANGE_EDIT_MODE_SETTING.is_equal(RANGEMODE_AU):
    397             scanRangeAU = ConvertKmToAu(scanRangeKM)
    398             self.ShowAUInput()
    399             self.auInput.SetMinValue(MIN_RANGE_AU)
    400             self.auInput.SetMaxValue(GetMaxRangeAU())
    401             self.auInput.decimalPlaces = 1
    402             self.auInput.SetValue(scanRangeAU)
    403             self.auInput.width = 45
    404             self.unitToggleButton.SetLabel(GetByLabel('UI/Inflight/Scanner/UnitAU'))
    405         else:
    406             self.ShowKMInput()
    407             self.kmInput.SetMinValue(ConvertAuToKm(MIN_RANGE_AU))
    408             self.kmInput.SetMaxValue(GetMaxRangeKM())
    409             self.kmInput.SetValue(scanRangeKM)
    410             self.unitToggleButton.SetLabel(GetByLabel('UI/Inflight/Scanner/UnitKm'))
    411             self.kmInput.width = 90
    412         self.UpdateUnitToggleButtonLabel()
    413 
    414     def ShowKMInput(self):
    415         self.kmInput.Show()
    416         self.auInput.Hide()
    417 
    418     def ShowAUInput(self):
    419         self.auInput.Show()
    420         self.kmInput.Hide()
    421 
    422     def OnRangeEditModeSettingChanged(self, *args):
    423         self.UpdateRangeInput(GetScanRange())
    424 
    425     def GetPresetOptions(self):
    426         presetSvc = sm.GetService('overviewPresetSvc')
    427         options = [(GetByLabel('UI/Inflight/Scanner/UseActiveOverviewSettings'), None)]
    428         for presetName in overviewUtil.GetCustomFiltersSorted() + overviewUtil.GetDefaultFiltersSorted():
    429             options.append((presetSvc.GetPresetDisplayName(presetName), presetName))
    430 
    431         return options
    432 
    433     def OnScanConeAligned(self):
    434         self.DirectionalScan()
    435 
    436     def OnBallparkSetState(self):
    437         if not self.destroyed:
    438             self.DirectionalScan()
    439 
    440     def OnAttributes(self, l):
    441         if self.destroyed:
    442             return
    443         for attributeName, item, newValue in l:
    444             if attributeName == 'maxDirectionalScanRange' and item.itemID == session.shipid:
    445                 self.UpdateMaxValue()
    446                 break
    447 
    448     def OnOverviewPresetSaved(self):
    449         uthread.new(self.UpdateScroll)
    450 
    451     def OnDirectionalScannerScanModeChanged(self, scanMode):
    452         self.UpdateAlignWithCameraBtn()
    453 
    454     def OnDirectionalScannerUndocked(self):
    455         self.mapButton.Show()
    456 
    457     def OnDirectionalScannerDocked(self):
    458         self.mapButton.Hide()
    459 
    460     def UpdateAngleSliderLabel(self, *args):
    461         startingAngle = int(round(math.degrees(GetScanAngle())))
    462         self.angleLabel.text = u'{}: {}'.format(GetByLabel('UI/Inflight/Scanner/Angle'), GetByLabel('UI/Inflight/Scanner/AngleDegrees', value=startingAngle))
    463 
    464     def OnScanRangeEditChange(self, *args):
    465         PlaySound('msg_newscan_directional_shape_play')
    466         self._UpdateScanRange()
    467 
    468     def OnScanRangeEditReturn(self):
    469         self._UpdateScanRange()
    470         self.DirectionalScan()
    471 
    472     def _UpdateScanRange(self):
    473         scanRangeAU = self._GetScanRangeAU()
    474         self.distanceSlider.SetValue(scanRangeAU)
    475 
    476     def _GetScanRangeAU(self):
    477         return self.distanceEditCont.GetScanRangeAU()
    478 
    479     def OnDirectionalScannerRangeChanged(self, range):
    480         value = ConvertKmToAu(range / 1000)
    481         if value > 0.5:
    482             value = round(value, 3)
    483         self.distanceSlider.SetValue(value)
    484         rangeInputFocused = self.distanceEditCont.IsRangeEditInFocus()
    485         if not rangeInputFocused:
    486             self.UpdateDistanceFromSlider()
    487 
    488     def UpdateDistanceFromSlider(self):
    489         scanRangeAU = self.distanceSlider.GetValue()
    490         self.distanceEditCont.SetScanRangeAU(scanRangeAU)
    491 
    492     def EndSetDistanceSliderValue(self, *args):
    493         self.UpdateDistanceFromSlider()
    494         PlaySound('msg_newscan_directional_shape_play')
    495         self._GetScanRangeAU()
    496         if not self.scanSvc.IsScanning():
    497             self.DirectionalScan()
    498 
    499     def OnSetDistanceSliderValue(self, slider, *args):
    500         if not slider.isDragging:
    501             return
    502         self.UpdateDistanceFromSlider()
    503 
    504     def EndSetAngleSliderValue(self, slider):
    505         angle = math.radians(slider.GetValue())
    506         PlaySound('msg_newscan_directional_shape_play')
    507         SetScanAngle(angle)
    508         if not self.scanSvc.IsScanning():
    509             self.DirectionalScan()
    510         self.UpdateAngleSliderLabel()
    511 
    512     def DirectionalScan(self, direction = None):
    513         uthread.new(self._DirectionalScan, direction)
    514 
    515     def _DirectionalScan(self, direction = None, *args, **kwds):
    516         self.scanSvc.DirectionalScan(direction)
    517 
    518     def OnDirectionalScanComplete(self, scanangle, scanRange, direction, results):
    519         self.scanresult = results
    520         uthread.new(self.AnimFlashOnScanDone)
    521         self.UpdateScroll()
    522 
    523     def AnimFlashOnScanDone(self):
    524         duration = 1.7
    525         animations.FadeTo(self.animBG, 1.0, 0.0, duration=duration)
    526         animations.MorphScalar(self.animBG, 'width', 1.0, 0.0, duration=duration)
    527 
    528     def OnDirectionalScanStarted(self):
    529         self.scanresult = []
    530 
    531     def UpdateScroll(self, *args):
    532         selectedValue = settings.user.ui.Get('scanner_presetInUse', None)
    533         if selectedValue is None:
    534             selectedValue = sm.GetService('overviewPresetSvc').GetActiveOverviewPresetName()
    535         filters = sm.GetService('overviewPresetSvc').GetValidGroups(presetName=selectedValue)
    536         ballpark = sm.GetService('michelle').GetBallpark()
    537         filtered = 0
    538         scrolllist = []
    539         if self.scanresult and ballpark:
    540             scanresult = self.scanresult[:]
    541             prime = []
    542             for celestialRec in scanresult:
    543                 if celestialRec.id not in ballpark.balls:
    544                     prime.append(celestialRec.id)
    545 
    546             if prime:
    547                 cfg.evelocations.Prime(prime)
    548             for celestialRec in scanresult:
    549                 if self.destroyed:
    550                     return
    551                 if celestialRec.groupID not in filters:
    552                     filtered += 1
    553                     continue
    554                 if not session.role & (ROLE_GML | ROLE_WORLDMOD):
    555                     if evetypes.GetGroupID(celestialRec.typeID) == appConst.groupCloud:
    556                         continue
    557                 entry = self.GetScrollEntry(ballpark, celestialRec)
    558                 scrolllist.append(entry)
    559                 blue.pyos.BeNice()
    560 
    561         filteredText = GetByLabel('UI/Inflight/Scanner/Filtered', noFiltered=filtered)
    562         activeFilterName = sm.GetService('overviewPresetSvc').GetDefaultOverviewDisplayName(selectedValue)
    563         self.filteredBox.SetText('%s (%s)' % (filteredText, activeFilterName))
    564         headers = DirectionalScanResultEntry.GetColumns()
    565         self.scroll.Load(contentList=scrolllist, headers=headers, noContentHint=GetByLabel('UI/Inflight/Scanner/DirectionalNoResult'))
    566 
    567     def GetScrollEntry(self, ballpark, celestialRec):
    568         typeName = evetypes.GetName(celestialRec.typeID)
    569         if evetypes.GetGroupID(celestialRec.typeID) == appConst.groupHarvestableCloud:
    570             entryname = GetByLabel('UI/Inventory/SlimItemNames/SlimHarvestableCloud', typeName)
    571         elif evetypes.GetCategoryID(celestialRec.typeID) == appConst.categoryAsteroid:
    572             entryname = GetByLabel('UI/Inventory/SlimItemNames/SlimAsteroid', typeName)
    573         else:
    574             try:
    575                 entryname = cfg.evelocations.Get(celestialRec.id).name
    576             except KeyError:
    577                 entryname = None
    578 
    579         if not entryname:
    580             entryname = typeName
    581         itemID = celestialRec.id
    582         typeID = celestialRec.typeID
    583         ball = ballpark.GetBall(celestialRec.id)
    584         if ball is not None:
    585             dist = ball.surfaceDist
    586             diststr = FmtDist(dist, maxdemicals=1)
    587         else:
    588             dist = 0
    589             diststr = '-'
    590         groupID = evetypes.GetGroupID(typeID)
    591         groupName = evetypes.GetGroupName(typeID)
    592         node = Bunch(__guid__='listentry.DirectionalScanResults', decoClass=DirectionalScanResultEntry, sortValues=(groupName,
    593          entryname,
    594          typeName,
    595          dist), charIndex=entryname, entryName=entryname, typeName=typeName, itemID=itemID, typeID=typeID, groupID=groupID, diststr=diststr)
    596         return node
    597 
    598     def SetMapAngle(self, angle):
    599         wnd = MapBrowserWnd.GetIfOpen()
    600         if wnd:
    601             wnd.SetTempAngle(angle)
    602 
    603     def EndSetSliderValue(self, *args):
    604         self.DirectionalScan()
    605 
    606 
    607 class FilterOptionEntry(MapViewCheckbox):
    608 
    609     def Startup(self, *args):
    610         MapViewCheckbox.Startup(self, *args)
    611         if self.sr.node.filterIndex is not None:
    612             shortcutObj = ShortcutHint(parent=self, text=str(self.sr.node.filterIndex), left=2, top=2)
    613             self.TEXTRIGHT = shortcutObj.width + 4